Overview
How the 8x Payout Gateway works end to end: the integration flow, the two money models, the rails, how you learn outcomes, the payout lifecycle, and test mode.
What the gateway is
The 8x Payout Gateway moves money to people across global rails. You integrate it the way you integrate Stripe: create a payee, send them to a hosted onboarding link, get a payee.updated webhook when they're payable, then call POST /payouts.
It is execution-only and custody-free: it owns payout identity, multi-rail routing, hosted onboarding, execution, and the transaction log. It never holds balances and never tracks what you owe your people — you keep that ledger, exactly as you do with Stripe. A payout request carries payeeId + amountCents, never a bank account: you decide who and how much, the gateway decides where.
The whole flow
Five steps take a creator from earned to paid:
Your platform 8x Payout Gateway Rail Creator
| upsertPayee ───────────▶ payee (payable:false)
| onboardingLink ────────▶ hosted URL ──────────────────────────▶ KYC / claim
| payee.updated (payable:true) ◀──────── webhook
| payout ────────────────▶ route + submit ───────▶ execute ─────▶ bank / wallet
| payout.status: submitted → paid ◀─────── settle ◀──────
| (backstop: poll GET /api/v1/payouts/{id} — a missed webhook is never fatal)1. Create the payee (upsertPayee, idempotent on your externalId). 2. Onboard — redirect or iframe them to the gateway-hosted onboarding link. 3. The gateway fires payee.updated when they become payable. 4. Pay — POST /payouts (or push owed rows via POST /disbursements). 5. Learn the outcome from payout.status webhooks, with polling as the backstop.
Grade (the default rail) is fully headless — skip step 2
upsertPayee; the payee comes back payable: true immediately — no onboarding link, no OTP, no payee.updated wait. Go straight from create → pay. Identity/KYC and payout-method choice happen inline on Grade's own claim link at withdraw time, which the gateway emails the creator (it is Grade's site, never the payouts gateway). Steps 2–3 apply only to hosted-onboarding rails like Stripe.Two ways money moves
Pick your entry point. Push pays a specific person now; pull credits a wallet the creator withdraws when they choose.
Push — you decide when to pay
POST /payouts (one) or POST /payouts/batch (the "email + amount" contract, up to 100 rows, 207 Multi-Status). A row for a not-yet-onboarded payee comes back held, not an error — onboard them, then release.
Pull — the owed wallet
POST /disbursements pushes what a creator earned; it holds as owed until an explicit withdraw (POST /payees/{id}/withdraw or the hosted portal). Idempotent on your externalRef per row.
The rails
Routing is server-side (a payee pin, an existing payable method, your source default, then a country matrix). Two families differ in how a creator onboards and when money releases:
Custodial (Stripe, Tipalti): hosted KYC up front — the creator becomes payable only after they finish, then owed balance auto-releases on that payable flip.
Custody-free (Grade, SideShift): payable by design; KYC and destination are collected inline at claim/withdraw time. SideShift auto-releases owed the moment it lands (the creator drains it to their bank in a second leg); Grade holds owed until an explicit withdraw, so a creator takes it as one consolidated claim.
Per rail
What each rail needs from the creator, and how the gateway learns the outcome. The API accepts USD only on every rail.
- Grade. Custody-free. No gateway-hosted onboarding: the creator verifies identity and picks a payout method on Grade's own site through the claim link on the
payout.statuswebhook (claimUrl), which the gateway also emails for direct payouts and owed releases. Payable by design, with no KYC up front. Settlement is learned by polling Grade. - Stripe. Custodial. Hosted-redirect onboarding on Stripe; payable once the creator finishes. No claim step. Settlement via Stripe webhooks with a reconcile poll as backstop.
- SideShift. Custody-free. Embedded-iframe onboarding. Owed money auto-releases into the creator's SideShift wallet, and the creator completes a second leg to their bank. Settlement via SideShift webhooks.
- Tipalti. Custodial. Embedded-iframe onboarding; payable once KYC completes. No claim step. Settlement is learned by polling.
- Mock. Test-mode clients only. Behaves as a custodial rail and settles instantly.
- Wise. In the provider enum but not available. Routing to it holds.
paid does not always mean the money landed
CLEARED; Grade only on a real landed date). Key off settledAt, not status: paid, when you need confirmed arrival.How you learn what happened
Three channels, three audiences — don't cross the wires:
Webhooks → you. payout.status on every status change and payee.updated on payability flips, signed with your secret (verify with PayoutClient.verifyWebhook). This is your integration signal. Delivery is at-least-once with retry; a missed one is never fatal — poll GET /payouts/{id} or readiness as the backstop.
Email → the creator. Credited, claim-link, on-its-way, landed, and failed emails go to the payee — never to you. Do not build your integration off them.
Slack → 8x ops. Internal alerting only; not part of your integration.
Payout status lifecycle
A payout runs requested → authorized → submitted → paid, with held, failed, and returned as the branches (paid and returned are terminal). A held payout is recoverable: read the leading snake_case token of statusReason, clear the blocker, and call POST /payouts/{id}/release. A failed payout with failureKind: transient is safe to retry. The full closed set of statusReason and error codes — with the remediation for each — is the Error & held-reason catalog in the contract.
The examples above use the legacy version 1 words. New clients default to status version 2 (the normalized vocab); Status versions lists the words you get and how they map.
Test mode
Test mode is a property of your client, same base URL. A test-mode client routes every payout and onboarding through the mock provider — synchronous settlement, no real KYC, no real money — so you can drive the entire contract end to end before going live: payouts, batches, disbursements → withdraw, adopting an existing method, and forcing then releasing a held payout.
For your coding agent
The complete, machine-readable contract is the OpenAPI 3.1 spec at /openapi.yaml — feed it straight to your agent. It carries every endpoint, request/response schema, the error & held-reason catalog, the status lifecycle, auth (Bearer + HMAC), the webhook events, rate limits, and the versioning policy in one file. /llms.txt indexes everything for LLMs.
The contract wins
openapi.yaml contract is the source of truth. Every guide, including this one, is a friendlier read of it — when they disagree, the contract wins.