List your payouts

GET
/api/v1/payouts

List this client's payouts, newest first, with cursor pagination. Filter by status.

Required scope: payouts:read.

Authorization

bearerAuth x8xTimestamp x8xSignature
AuthorizationBearer <token>

Your client API key. Authorization: Bearer <API key>. The gateway stores only sha256(key); keys are rotatable and revocable.

In: header

x-8x-timestamp<token>

Unix time (seconds) at which the request was signed. Must be within 300s of gateway time.

In: header

x-8x-signature<token>

Hex HMAC-SHA256(signingSecret, "{timestamp}.{rawBody}") over the exact raw request body (empty string for GET). Defeats tampering and replay.

In: header

Query Parameters

limit?integer

Page size, 1–100. Defaults to 100; values above 100 are clamped.

Range1 <= value <= 100
Default100
cursor?string

Opaque pagination cursor — pass back the nextCursor from the previous page to fetch the next. It is the ISO-8601 createdAt of the last row returned. The boundary is exclusive (rows strictly older than this createdAt). createdAt is not guaranteed unique; rows sharing the boundary createdAt may be skipped. Treat the cursor as opaque and stop when nextCursor is null.

Formatdate-time
status?string

Filter by payout status. Takes version 1 (PayoutStatus) words even when your client uses status version 2, because the filter matches the internal status.

Value in

  • "requested"
  • "authorized"
  • "submitted"
  • "paid"
  • "failed"
  • "returned"
  • "held"

Response Body

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 page = await client.listPayouts({ status: 'held', limit: 50 });for (const txn of page.data) console.log(txn.id, txn.statusReason);
{  "data": [    {      "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"    }  ],  "nextCursor": "2019-08-24T14:15:22Z"}

Withdraw the payee's held balance as one consolidated payout POST

Release **every still-`owed` disbursement** for this payee as a **single consolidated payout** — the money credited to their wallet and held until they choose to take it. This is the API-key counterpart to the creator pressing **Withdraw** in the hosted portal: the same release spine, the same consolidation, the same gates. Use it when you keep your own wallet UI and want an in-app "Withdraw" button to trigger the payout rather than routing the creator to the portal. **Held-by-default (per rail).** Grade holds credited money as `owed` in the wallet until an explicit withdraw (so a creator who earned across cycles takes it as ONE payout and ONE claim link). SideShift auto-releases owed into its managed wallet the moment the credit lands; the creator drains it (leg-2) later. Stripe/Tipalti auto-release only when payability flips false→true (KYC completes). Auto-release is a per-rail behavior, not a property of "custody-free rails" as a class. **No body:** a wallet withdraws what is in it; the amount, rail and consolidation are resolved server-side. Refuses with `409` if the payee is not yet payable (KYC incomplete) or a per-source min/max/frequency policy blocks it — nothing is released in that case. **Required scope:** `disbursements:write`.

Create a payout POST

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`.