Reference
API errors
Find the response code and the safe next step.
Read the code, not just the status
Customer-access errors include error.code and error.message. Participation endpoints return error.code only. Use the code for logic; do not depend on message wording. Responses are not publicly cacheable.
{
"error": {
"code": "invalid_api_key"
}
}Merchant-authenticated endpoints use Authorization: Bearer rs_…. Report/visit endpoints use their purpose-specific signed token in the JSON body, not the API key. Standard limits are 120 requests per API key and 300 per IP per minute. Public report/visit endpoints have their own IP limits. Back off on HTTP 429.
Enrolment, widget and participation changes
| HTTP / code | Safe next step |
|---|---|
| 400 invalid_request | Send valid JSON with customer_id (cus_…). PATCH also needs active as a boolean. |
| 401 invalid_api_key | Check the server secret and workspace; replace a revoked key. Do not expose it to the browser. |
| 402 programme_paused | Owner checks billing and the connected Stripe account. A retry loop cannot restore access. |
| 409 no_programme | Save Programme before requesting customer access. |
| 409 customer_deactivated | Only explicit owner/API reactivation enables new participation. |
| 409 enrolment_ceiling_reached | Check Billing or contact support. Do not repeatedly retry the same enrolment. |
| 409 lifecycle_busy | Finish/retry the same participation change before requesting its opposite. |
| 422 unknown_customer | Confirm the customer exists in this connected Stripe account and mode. PATCH also requires prior enrolment. |
| 429 rate_limited | Back off and try again in a minute. Avoid parallel retry bursts. |
| 503 lifecycle_sync_failed | Retry the same change. Provider promotion-code status is not yet confirmed; do not claim it succeeded. |
Moments, reports and prompt context
| HTTP / code | Safe next step |
|---|---|
| 400 invalid_request | Use the documented fields and values; moment/report bodies must fit 4,096 bytes. |
| 400 invalid_event_time | Check trusted timestamps: at most seven days old, five minutes future; account creation cannot be future. |
| 401 invalid_api_key | Use a valid server API key on moments or referral-context. |
| 401 invalid_token | Token missing, expired, malformed, wrong purpose or wrong workspace. Fetch the appropriate fresh capability; never extend an old decision. |
| 409 programme_paused | Moment connection changed or is unavailable. Check connection and programme access. |
| 409 no_programme | Save Programme first. |
| 409 event_key_conflict | The key already identifies another customer or moment. Fix your event identity mapping; do not randomise all retries. |
| 409 decision_unavailable | Report/observation no longer permitted or reservation expired. Hide the prompt. Never fabricate shown/copy outcomes. |
| 409 referral_not_found | Wait for the friend's referral webhook, then retry the same context attachment. |
| 422 customer_not_enrolled | Enrol this customer in the connected account/mode before sending moments. |
| 422 unknown_moment | Save the exact moment name in Programme. |
| 422 unknown_customer | Stripe cannot verify that customer in the connected account. |
| 429 rate_limited | Back off before retrying; keep the original event key. |
| 503 moment_unavailable | Temporary processing failure. Retry the identical event key, not a newly generated event. |
changed: false on an observation is not automatically an HTTP error. It can mean duplicate or inapplicable context. Do not reinterpret it as attribution failure or issue a reward yourself. A skipped moment response is also successful HTTP: read its decision reason.
Keep retries safe
After a network timeout, the write may have succeeded. Reuse the event key, report token/outcome or lifecycle target. Respect created and changed; only the first accepted write counts.
Never log API keys, signed URLs, report/context tokens, customer emails or full Stripe objects. Give support the endpoint, time, HTTP code, error code, test/live mode and any non-secret decision ID.