v1.7.0
OpenAPI 3.1.0

Roster Partner API

The Roster Partner API lets a platform partner import its churches, open hosted donor sessions, read enrollment status, and reconcile through an event feed plus signed outbound webhooks.

Conventions (apply to every endpoint)

  • Authentication — every /v1/* and /sandbox/* request needs Authorization: Bearer sk_test_... (sandbox) or Bearer sk_live_... (production). Test keys only exist on the sandbox stack. A malformed, unknown, or wrong-mode key always gets the same opaque 401.
  • Idempotency — the Idempotency-Key header (1–255 visible ASCII characters, no spaces) is required on every POST. Keep the key stable when retrying the same action with the same body: a repeated creation returns the original resource (200) and changes nothing. A key belongs to the first body sent with it, from the moment that request arrives: the same key with a different body on the same operation gets 409 idempotency-key-reused for 30 days, and nothing runs — use a new key for a new request. This holds while the first request is still running and after it ends in a 5xx or a timeout: repeat it with the same body and the same key to complete it. A request refused with 400 (or any other 4xx) does not hold the key: fix the body and repeat it with the same key — unless an earlier attempt with that key already ended in a 5xx or a timeout; then the key stays with that body, and the corrected request needs a new key. 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. Webhook tests run again on every call with the same body, and so do sandbox simulators while what they check still holds, except the simulated deposit, which does not credit twice. Once a first call changed it, a repeat answers 400 naming what it found: a payroll simulator, the state the enrollment reached; the identity simulator, the donor's final outcome; the account-closure simulator, the closed account; the late-return simulator, the leg already returned; the refund simulator, the refund's status. The per-operation table is in the reliability guide.
  • Errors — RFC 7807 application/problem+json: {type, title, detail, request_id}. Every response the API sends to an authenticated call, success included, also carries the same reference in the X-Request-Id header. Include it when contacting support. The gateway in front of the API answers four cases on its own, without X-Request-Id, Roster-Api-Version, RateLimit-* or a problem body: its throttle shared by every partner (429, {"message":"Too Many Requests"}), a call the API did not answer in time (500 or 503), a path it cannot parse, such as one containing %zz (400 with an HTML body), and a browser preflight (OPTIONS, 403 with an empty body: call the API from your backend). See API errors.
  • Request bodies — JSON sent with Content-Type: application/json, up to 1 MiB. A body in another format, over the limit, or that is not valid JSON gets 400 bad-request, with the reason in detail. An empty body counts as no body.
  • Rate limiting — a per-partner quota (600 requests per minute, fixed window, shared by all your keys) on top of the gateway's global throttle. Every response the API sends to an authenticated call carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds until the window resets); past the quota, expect 429 with Retry-After and no side effect. A 429 from the gateway's throttle carries none of these headers (see Errors above).
  • Pagination — cursor-based: the event feeds take since_cursor, the church and enrollment lists take cursor, and each returns next_cursor. Cursors are opaque; never construct one.
  • Reading what Roster sends — responses, webhook deliveries and event payloads can gain fields, enum values and event types at any time: that is an additive change, listed in the changelog. Ignore fields you do not recognize, treat an enum value you do not recognize as "something changed; read the resource again", and skip event types you do not handle. The response and event schemas here are open to new fields on purpose, and an enum lists the values sent today: if you generate a validator or a typed client, keep it accepting what it does not know.
  • Versioning — the contract follows semantic versioning: info.version above is MAJOR.MINOR.PATCH, and every response the API sends carries it in the Roster-Api-Version header. A breaking change ships only in a new major, under a new path prefix (/v1 is major 1); a minor only adds; a patch fixes documentation or behavior without changing the contract. A published version never changes. The newest generally available major is the Default; when a new major replaces it, the previous one becomes LTS for 12 months, with security and critical fixes only. See the changelog.
  • Donor data — financial events include authorized donor name, contact and mailing address for partner reporting and existing ChMS integrations. Activity events and enrollments retain their narrower allowlists. Raw payroll data and donor bank credentials are not part of this contract.

Certification flow (sandbox, self-service)

GET /sandbox/fixtures returns every test value used below. The full script, with the other scenarios, is in the certification guide.

  1. Register a webhook endpoint (POST /v1/webhook_endpoints), store its secret, and prove your receiver with POST /v1/webhook_endpoints/{id}/test.
  2. Register the sites where your pages open the hosted flow (PUT /v1/allowed_origins): only a registered site can show the flow inside its pages.
  3. Create or import a church (POST /v1/churches or POST /v1/churches/import). Do not send a test EIN there.
  4. Verify the church. Send its legal details with a test EIN from 00-0000001 to 00-0000093 and an incorporation date at least six months ago (POST /v1/churches/{id}/verification), and its receiving account with routing number 021000021 and an account number that does not end in 00, 11 or 22 (POST /v1/churches/{id}/bank-account). Read GET /v1/churches/{id} until payout_ready is true: donors cannot start paycheck giving at a church Roster has not verified.
  5. Open a donor session (POST /v1/donor_sessions) and complete the hosted flow on a registered site as a test donor: any number from +1 202-555-0100 to +1 202-555-0189, any adult date of birth, code 000000. Numbers 0190 to 0199 keep the identity check in review, and step 6 refuses them. You receive enrollment.created.
  6. Connect the payroll in the hosted flow, through the payroll provider's window in its test mode, or, from a script that does not drive that window, simulate the payroll connection (POST /sandbox/simulate/payroll-connected). Receive enrollment.activated on your webhook endpoint.
  7. Cross-check the same event on the pull feed (GET /v1/events).

Sandbox — sk_test keys; includes /sandbox simulators.

Client Libraries