Skip to main content

Testing Your Integration

Before going live with billing, you need to verify that events are processed correctly, invoices calculate as expected, and payments flow through. This guide covers test mode, verification strategies, and common debugging techniques.
Testing billing is critical—mistakes result in incorrect charges. Take time to verify each step before enabling auto-pay or sending invoices to real customers.

Test Mode vs Live Mode

Monk supports two API key modes:
ModeAPI Key PrefixPurposeStripe Environment
Testmk_test_...Development and testingStripe Test Mode
Livemk_live_...Production billingStripe Live Mode

Using Test Mode

  1. Navigate to Settings → API Keys in your dashboard
  2. Create or copy your test API key (mk_test_...)
  3. Use this key for all development and testing
Test mode data is completely isolated from live mode. Create test customers, plans, and contracts without affecting production billing.

Switching Between Modes

Your dashboard shows which mode you’re viewing. Toggle between Test and Live mode to see the respective data:
  • Test mode: Orange indicator in dashboard
  • Live mode: No indicator (production default)

Testing Checklist

Use this checklist to verify your integration end-to-end:
1

Create test resources

Set up a test customer, meter, plan, and contract
2

Send test events

Send usage events via API and verify they’re received
3

Verify event processing

Confirm events match to the correct invoice
4

Check invoice calculations

Verify line items and totals are correct
5

Test payment flow (optional)

For auto-pay, test with Stripe test cards

Step 1: Set Up Test Resources

Create a minimal billing setup for testing:

1.1 Create a Test Customer

curl -X POST "https://api.monk.com/v1/customers" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Test Customer",
    "externalCustomerId": "test_cust_001"
  }'
Note the returned id—you’ll need it for sending events.

1.2 Create a Test Meter

In your dashboard (Test mode):
  1. Navigate to Products → Meters
  2. Create a meter:
    • Code: TEST_API_CALLS
    • Display Name: “Test API Calls”
    • Aggregation: Sum

1.3 Create a Test Plan

  1. Navigate to Products → Plans
  2. Create a plan:
    • Name: “Test Plan”
    • Net Terms: Due on receipt (Net 0)
  3. Add a usage-based price linked to TEST_API_CALLS
    • Price: $0.01 per unit

1.4 Create a Test Contract

curl -X POST "https://api.monk.com/v1/contracts" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "planId": "your-test-plan-id",
    "customerId": "your-test-customer-id",
    "startDate": "2026-02-01"
  }'
Use a start date in the past or today to immediately have an active billing period for testing.

Step 2: Send Test Events

Send usage events and verify they’re accepted.

Single Event

curl -X POST "https://events-api.monk.com/v1/events" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "your-test-customer-id",
    "event_name": "test_api_calls",
    "idempotency_key": "test_event_001",
    "properties": {
      "endpoint": "/api/users",
      "method": "GET"
    }
  }'

Expected Response

{
  "status": "accepted",
  "idempotency_key": "test_event_001",
  "request_id": "req_abc123"
}

Batch Events

curl -X POST "https://events-api.monk.com/v1/events/batch" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      {
        "customer_id": "your-test-customer-id",
        "event_name": "test_api_calls",
        "idempotency_key": "test_event_002"
      },
      {
        "customer_id": "your-test-customer-id",
        "event_name": "test_api_calls",
        "idempotency_key": "test_event_003"
      }
    ]
  }'

Step 3: Verify Event Processing

After sending events, verify they were processed correctly.

Check the Events List

  1. Navigate to Usage-based → Events in your dashboard
  2. Find your test events in the list
  3. Verify:
    • Event name matches your meter
    • Customer is correctly attributed
    • Timestamp is correct
Usage-Based Events tab showing a list of usage events with timestamp, event name, properties JSON, and customer name

Common Event Issues

SymptomLikely CauseSolution
Event not in listWrong API key modeVerify using mk_test_... key
Customer shows as “Unknown”Invalid customer_idCheck customer exists in test mode
Event name doesn’t matchMeter code mismatchEnsure event_name matches meter code exactly
Duplicate rejected (409)Same idempotency_key sent twiceExpected behavior—original event was processed

Step 4: Verify Invoice Calculations

Check that events update the correct invoice.

View the Invoice

  1. Navigate to Customers → Select your test customer
  2. Find the active contract
  3. Click on the current period’s invoice
  4. Verify:
    • Usage quantity matches events sent
    • Line item total is calculated correctly
    • Invoice total is accurate

Expected Calculation

For our test setup (3 events × $0.01/unit):
Line ItemQuantityUnit PriceTotal
Test API Calls3$0.01$0.03
Total$0.03

Invoice Not Updating?

If your invoice doesn’t reflect the events:
  1. Wait a few seconds — event processing is asynchronous
  2. Refresh the page — invoice totals are cached briefly
  3. Check contract status — must be “Active” (not Scheduled or Cancelled)
  4. Verify billing period — event timestamp must fall within the invoice’s service period
  5. Check meter → plan linkage — the meter must be linked to a pricing item in the plan
Events outside the billing period won’t match to the invoice. If your contract started March 1 and you send an event with a February timestamp, it won’t appear on the March invoice.

Step 5: Test the Full Billing Cycle

For a complete end-to-end test, simulate a full billing cycle.

Test Scenario

  1. Day 1: Create contract starting today
  2. Day 1-30: Send usage events throughout the period
  3. Day 30: Invoice finalizes with all usage
  4. Day 30+: (If auto-pay) Payment is collected

Using Stripe Test Cards

If testing auto-pay, use Stripe’s test cards:
Card NumberScenario
4242424242424242Successful payment
4000000000000002Card declined
4000000000009995Insufficient funds
4000000000000341Attaches but fails
See Stripe’s test card documentation for more scenarios.

Debugging Event Processing

When events don’t appear on invoices as expected, follow this debugging flow.

1. Verify the Event Was Received

Check the Events list in your dashboard. If the event isn’t there:
  • Confirm you received a 202 Accepted response
  • Check you’re viewing the correct mode (Test vs Live)
  • Verify the API key matches the mode

2. Check Customer Attribution

If the event shows “Unknown Customer”:
  • Verify customer_id or external_customer_id is correct
  • Confirm the customer exists in the same mode (Test/Live)
  • Check for typos in the customer ID

3. Verify Contract Exists

The customer must have an active contract:
  • Navigate to the customer’s page
  • Check for an active contract covering the event’s timestamp
  • Verify the contract’s plan includes pricing for the meter

4. Check Meter → Plan Linkage

The event’s event_name must match a meter that’s linked to the plan:
event_name: "test_api_calls"

Meter code: "TEST_API_CALLS" (case-insensitive match)

Plan pricing item linked to this meter

Invoice line item updated

5. Verify Timestamp Is in Billing Period

Events are matched to invoices based on timestamp:
  • Invoice covers March 1–31
  • Event timestamp: March 15 → ✅ Matches
  • Event timestamp: February 28 → ❌ No match (wrong period)
  • Event timestamp: April 1 → ❌ No match (wrong period)
When testing, omit the timestamp field to use the current time, which will always fall within an active billing period.

Testing Idempotency

Verify that duplicate events are handled correctly.

Send the Same Event Twice

# First request - should succeed
curl -X POST "https://events-api.monk.com/v1/events" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "your-test-customer-id",
    "event_name": "test_api_calls",
    "idempotency_key": "duplicate_test_001"
  }'

# Response: { "status": "accepted", "idempotency_key": "duplicate_test_001" }

# Second request with same key - also accepted - safe to retry
curl -X POST "https://events-api.monk.com/v1/events" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "your-test-customer-id",
    "event_name": "test_api_calls",
    "idempotency_key": "duplicate_test_001"
  }'

# Response: { "status": "accepted", "idempotency_key": "duplicate_test_001" }

What This Means

  • Both requests return 202 Accepted — retries are always safe
  • Monk uses the latest version of an event with the same idempotency key for billing
  • Your invoice won’t be double-charged; duplicate keys are deduplicated automatically

Testing Error Scenarios

Intentionally trigger errors to verify your error handling.

Invalid Customer

curl -X POST "https://events-api.monk.com/v1/events" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "nonexistent-customer-id",
    "event_name": "test_api_calls"
  }'

# Response: 404 - { "error": { "code": "CUSTOMER_NOT_FOUND", ... } }

Missing Required Fields

curl -X POST "https://events-api.monk.com/v1/events" \
  -H "Authorization: Bearer mk_test_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "event_name": "test_api_calls"
  }'

# Response: 400 - { "error": { "code": "VALIDATION_ERROR", ... } }

Verify Your Code Handles These

Your integration should:
  1. Log errors for investigation
  2. Queue for retry on 5xx errors (server issues)
  3. Alert on 4xx errors (client issues that need fixing)
  4. Never lose events due to transient failures

Pre-Launch Checklist

Before switching to live mode:
  • Events are sent in real-time (or batched appropriately)
  • Idempotency keys are unique and deterministic
  • Error handling queues failed events for retry
  • Logging captures event send/receive for debugging
  • Meters are created with correct aggregation - [ ] Plans have correct pricing items linked to meters - [ ] Net terms match your billing requirements
  • Auto-pay is configured correctly (if applicable)
  • Customers are linked to Stripe (for auto-pay) - [ ] External customer IDs match your system - [ ] Payment methods are saved for auto-pay customers
  • Events appear in the dashboard
  • Invoices calculate correctly
  • Payment flow works (test cards)
  • Webhooks are received (if configured)

Going Live

When you’re ready for production:
  1. Create live resources: Recreate your meters, plans in live mode (or verify they exist)
  2. Switch API keys: Replace mk_test_... with mk_live_... in your production environment
  3. Verify first events: Send a few live events and verify they appear
  4. Monitor closely: Watch for errors in the first few days
Double-check your API key before sending live events. Using a test key in production means events won’t be billed. Using a live key in development means real charges.

Next Steps

Send your first Event

Detailed guide on event integration

Set up Webhooks

Receive real-time billing notifications

API Reference

Full API specification

Billing for SaaS

Complete end-to-end setup guide