Create a payout
Create — or idempotently re-fetch — a payout. Exactly-once on
(yourClient, idempotencyKey): re-sending the same idempotencyKey returns
the existing transaction (HTTP 200), never a second payout. A brand-new
payout returns HTTP 201.
The body carries no destination — the gateway resolves the rail from the
payee's KYC-locked identity. If the payee isn't payable, the rail isn't built,
a per-client rail allow-list excludes the resolved rail, or an operational
ceiling is exceeded, the transaction is created in a non-terminal state
(held / failed) and returned — inspect status. On a provider
timeout/5xx the transaction stays submitted (never silently failed) for
the reconcile cron to resolve.
Required scope: payouts:write.
Authorization
bearerAuth x8xTimestamp x8xSignature Your client API key. Authorization: Bearer <API key>. The gateway stores
only sha256(key); keys are rotatable and revocable.
In: header
Unix time (seconds) at which the request was signed. Must be within 300s of gateway time.
In: header
Hex HMAC-SHA256(signingSecret, "{timestamp}.{rawBody}") over the exact raw
request body (empty string for GET). Defeats tampering and replay.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
import { PayoutClient } from '@8x-payout/sdk';const client = new PayoutClient({ baseUrl: process.env.PAYOUT_BASE_URL!, apiKey: process.env.PAYOUT_API_KEY!, signingSecret: process.env.PAYOUT_SIGNING_SECRET!,});const txn = await client.payout({ payeeId, amountCents: 100, // integer cents: $1.00 currency: 'USD', idempotencyKey: 'settle-invoice-123', // re-sending returns this same txn ref: 'invoice_123', // echoed on the payout.status webhook reason: 'October creator payout',});console.log(txn.status); // 'paid' | 'submitted' | 'held' | 'failed' on status version 1; version 2 reads 'sent' or 'awaiting_withdraw' instead of 'submitted'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "source": "string", "payeeId": "79417842-2e1e-4110-a361-89b9f39b36ed", "idempotencyKey": "string", "amountCents": 0, "currency": "string", "status": "requested", "provider": "stripe", "providerRef": "string", "reason": "string", "ref": "string", "failureKind": "transient", "retryable": true, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "liftingFeeCents": 0, "claimUrl": "string"}List your payouts GET
List this client's payouts, newest first, with cursor pagination. Filter by `status`. **Required scope:** `payouts:read`.
Create many payouts in one call POST
Pay many people in a single signed request — the **email + amount** contract. Each item identifies a payee by **`payeeId`** (one you own) **or** by **`email`** (the gateway resolves-or-creates a payee keyed by that email), plus an `amountCents`. As always the body carries **no destination** — each rail is resolved server-side from the payee's KYC-locked method. The response is **`207 Multi-Status`** with one entry per row, in request order: `status: ok` carries the created/replayed `transaction` (inspect its own `status` — an un-onboarded `email` row comes back `held`), `status: error` carries a stable `error` code from the closed per-row enum on `BatchPayoutResultItem.error`. A failing row **never** aborts the others. **Exactly-once.** Each row's idempotency key is its own `idempotencyKey` when set, else it is derived from the batch key and the row's **payee identity** (not its array position). So re-sending the same batch key with rows added, removed, or reordered replays the rows already paid and pays only the genuinely new ones — it never double-pays. Two rows targeting the **same** payee without explicit per-row keys are ambiguous and rejected (`400 duplicate_target`); give them distinct `idempotencyKey`s to pay the same payee twice in one batch. **Required scope:** `payouts:write`. Items that use `email` (which mint a payee identity) additionally require `payees:write`.