Developers
Errors and testing
The Soca error envelope and every error code, SocaError in the SDK, test mode isolation, idempotency keys, cursor pagination, and how to handle rate limits.
The error envelope
Every API error is JSON in one shape: a machine-readable code and a human-readable message that names the offending field where relevant:
Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing, malformed, invalid, or revoked API key. See Authentication. |
| 400 | invalid_json | The request body is not valid JSON. |
| 400 | invalid_request | The body failed validation. The message says which field and why. |
| 400 | mode_mismatch | The key's mode (test/live) does not match the environment the request was sent to. |
| 400 | amount_too_small | Below the minimum. Plans require at least 1.00 USDC (1000000 base units). |
| 400 | invalid_interval | The plan interval / interval_days combination is not valid. |
| 400 | missing_value | The meter is not count-aggregated, so the event needs a numeric value. |
| 400 | customer_required | Credit grants/debits and entitlement grants need customer_id or external_customer_id. |
| 400 / 404 | unknown_customer | No such customer in this account. 400 when referenced in a request body; 404 when it is the {id} in a URL path. |
| 404 | unknown_meter | No meter with that event_name. Create it in the dashboard first. |
| 404 | unknown_feature | No feature with that feature_key in this account. |
| 404 | no_credit_account | The customer has no credit account yet. Grant credits before debiting. |
| 404 | resource_not_found | Unknown /v1/{resource}. Valid list resources: payments, subscriptions, invoices, events, meters. |
| 405 | method_not_allowed | POST to a read-only resource; only invoices and plans are creatable. |
| 429 | rate_limited | Too many requests. See the limits table in Authentication and the handling advice below. |
SocaError in the SDK
The SDK turns every non-2xx response into a thrown SocaError with the envelope's code and the HTTP status:
Test mode
Your account has two parallel environments, selected purely by key prefix: sk_test_ and sk_live_. Everything is isolated per mode: invoices, plans, payments, customers, meters, credits, entitlements, events, webhooks, and integrations. Build the whole flow against a test key, walk a test checkout end to end, watch the test webhooks arrive, then swap in a live key, no other change is needed, and test data can never contaminate live reports.
Idempotency keys
The endpoints that get retried under load accept an idempotency key in one of two places: an idempotency_key field in the body or an Idempotency-Key request header.
POST /v1/meter-events: per event (in a batch, use the body field on each event).POST /v1/credit_grantsandPOST /v1/credit_debits.
A replay with the same key returns 200 with deduplicated: true and does not double-count, double-grant, or double-debit, so on a timeout or a 5xx, simply retry with the same key. Keys can be up to 255 characters; derive them from something naturally unique in your system (a request ID, "{customer}:{period}:{reason}", and so on).
Pagination recipe
Every list endpoint returns { object, data, has_more, next_cursor } and accepts limit (1–100, default 25) and before (an ISO timestamp cursor). To walk an entire collection, loop until has_more is false:
Handling rate limits
- A
429response includes aretry-afterheader in seconds. Wait at least that long before retrying, and add jitter if many workers share the limit. - For usage metering, prefer batching: one
POST /v1/meter-eventscall carries up to 500 events, which turns the 600/min ingestion budget into hundreds of thousands of events per minute. - Cache entitlement checks briefly (seconds to a minute) if you gate a hot code path. The check endpoint allows 600/min, but a short-lived local cache removes the ceiling entirely.
- Retries of idempotent writes are always safe when you reuse the idempotency key.
Was this page helpful?
A quick signal helps us improve the right pages.