Errors, retries and production readiness
Your integration must survive a timeout after a successful write. Record the business action and its idempotency key before sending the request, and keep enough state to investigate an ambiguous response without issuing a new action.
Decide whether to retry
| Outcome | Action |
|---|---|
400 |
Correct the request using its problem detail and the endpoint schema |
401 |
Check the environment and credential; retrying unchanged will not help |
404 |
Check the ID and partner ownership; an ID belonging to another partner is also hidden |
409 |
Inspect the problem type, the operation's conflict conditions and resource state |
410 on a hosted donor link |
The link is expired, already used, or opened from a site that is not in your allowed origins. Check GET /v1/allowed_origins first; see gone |
429 |
Respect Retry-After; your keys share the partner quota |
Timeout or 5xx |
Treat the outcome as unknown; check state and follow the operation's replay contract |
Every POST requires Idempotency-Key. A key belongs to the first body sent with it on that operation, for 30 days from the moment that request arrives: the same key with a different body gets 409 idempotency-key-reused, and nothing runs. That holds while the first request is still running and after it ends in a 5xx or a timeout: repeat the same body with the same key to complete it, and send a corrected body with a new key. A request refused with 400 (or any other 4xx) does not hold the key, so you can fix the body and repeat it with the same key, unless an earlier attempt with that key ended in a 5xx or a timeout. On an operation that creates a resource — POST /v1/churches, POST /v1/churches/import, POST /v1/church_consents, POST /v1/donor_sessions, POST /v1/manage_sessions, POST /v1/refunds and POST /v1/webhook_endpoints — a key whose request succeeded also keeps its body for as long as the resource it created exists: a different body gets 409 even after the 30 days, and the same body still returns the original resource. On the other operations, the key is held for the 30 days only. A repeat with the same body is not a universal cached-response guarantee: what it does depends on the operation.
| Operation | Same key and body again | Also deduplicated by |
|---|---|---|
POST /v1/churches |
200 with the same church |
reference: a new key with a known reference returns that church |
POST /v1/churches/import |
200; each row already created comes back replayed |
Each row's reference, as above |
POST /v1/church_consents |
200 with the consent first recorded |
Church, document and version, whatever the key |
POST /v1/churches/{id}/verification |
202 with the same request_id |
— |
POST /v1/churches/{id}/bank-account |
The same account answers already_verified once it is verified; in production, pending until Roster confirms it |
The account itself, whatever the key |
POST /v1/donor_sessions, /v1/manage_sessions |
200 with the same session, without url |
— |
POST /v1/webhook_endpoints |
200 with the same endpoint, without secret, even after you deleted it (status: deleted); use a new key to register again |
— |
POST /v1/webhook_endpoints/{id}/test |
Sends a new test delivery | — |
POST /v1/refunds |
200 with the same refund, in its current state |
— |
POST /v1/refunds/{id}/cancel |
200 with the canceled refund |
— |
| Sandbox simulated deposit | The same deposit, not a second credit | trace: one already used for another deposit gets 400 |
Other sandbox simulators (/sandbox/simulate/…) |
Runs again while its prerequisite holds. Once the first call changed the enrollment's status, the payroll simulators answer 400 naming the state it reached, and the refund simulator answers 400 naming the refund's status: read that as done |
— |
Use a new key for a new intent, and the same key and body to retry an uncertain request. A key derived from too little — the church but not the donor, say — is the usual cause of idempotency-key-reused: the 409 is what keeps it from handing you another request's resource. Simulator acceptance is not proof that downstream processing finished: check the result before repeating a simulation.
Use bounded retry attempts with exponential backoff and jitter where retry is appropriate. Surface exhausted retries to an operator. Do not retry forever or create new keys to get around errors. The JavaScript client example, https://docs.rostergiving.com/examples/partner-client.mjs, deliberately leaves retry decisions to your application and refuses redirects so credentials are not forwarded to another host.
Credentials and logs
Use sandbox sk_test_… keys with https://api.sandbox.rostergiving.com, and production sk_live_… keys with https://api.rostergiving.com, which opens when Roster releases your production workspace. The workspace owner manages keys on the API keys page of the partner portal. Rotation replaces credentials: coordinate the change across your backend and MCP clients, then prove the new key works. Do not assume the old key remains valid during an overlap period.
Log status, duration, operation, safe resource IDs and request_id. Redact Authorization, webhook secrets, donor session URLs, phone numbers and bank details. When escalating a failure, provide the environment, UTC time, operation and request_id; never send a credential or a raw request containing personal information.
Release gates for a partner
Production is a separate workspace with its own portal and its own keys. Roster releases it once the commercial agreement is signed; the four certification scenarios are recommended checks, not a gate. A sk_live_… key can be issued only after that release and once your payout account is confirmed; Roster confirms the payout account by hand.
Passing the four certification scenarios proves enrollment lifecycle behavior. Before enabling production traffic, also demonstrate:
- Your church import accounts for every row and can resume without duplicates.
- Consent records reflect actual acceptance and church bank readiness is confirmed.
- Hosted URLs reach the intended donor without leaking through logs or analytics.
- Webhook signatures reject tampering and stale timestamps; acknowledgment follows durable acceptance.
- Reconciliation resumes after a restart and after missed or duplicate webhooks.
- Rate limits, invalid or lost cursors and unavailable upstream services produce actionable alerts.
- Production credentials, registered sites (
PUT /v1/allowed_origins) and webhook destination are configured for production, with a named owner for incidents.
Keep sandbox enrollment tests separate from validation of deposits, returns and money delivered to a church. Activation does not certify the financial lifecycle. Run the financial scenarios with test churches and donors before claiming that path is ready.