Create a hosted onboarding link
Get a gateway-hosted, rail-agnostic onboarding URL for a payee — like a
Stripe account link. Redirect your (already-authenticated) creator to the
returned url, or embed it as an iframe; they need no separate gateway
login. The URL points at the gateway's own /onboard page carrying a
short-lived signed token — never at Tipalti/Stripe directly — and the gateway
renders the right rail behind it.
returnUrl is where the creator is sent when they finish. It must be an
absolute https URL whose host is either your registered webhook domain
(the host of your configured webhook URL) or the gateway's own origin;
anything else is rejected at request time with 400 invalid_return_url
(open-redirect protection). Localhost over http is allowed in non-production
environments only. When the payee becomes payable, the gateway fires a
payee.updated webhook.
The onboarding experience depends on the payee's resolved rail. Custodial rails
(Stripe, Tipalti) run hosted KYC and payout-method setup up front — the payee
becomes payable only after they finish, at which point payee.updated fires.
Custody-free rails (Grade, SideShift) are payable-by-design at account creation;
KYC and method selection happen inline at claim/withdraw time via the claim link
the payout produces, so there is no method to pre-set here.
Required scope: onboarding: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
Path Parameters
The gateway payee id.
uuidRequest 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
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 { url, provider } = await client.getOnboardingLink( payeeId, 'https://yourapp.example.com/payouts/onboarded', // returnUrl on YOUR domain);// Redirect the creator to `url` (or pass mode: 'iframe' to embed it).{ "url": "http://example.com", "mode": "redirect", "provider": "stripe"}Adopt an existing provider account as a payout method POST
Attach an **already-KYC'd** provider account — a Stripe Connect `acct_…` on the gateway's own platform, or a Tipalti payee id under the gateway's payer — as this payee's payout method, bypassing hosted onboarding entirely. Use this when you're migrating a creator who is already verified on the rail directly. This is the gateway's trust boundary: the caller's payability claim is **never** believed. The gateway reads the account **live** from the rail (Stripe: `charges_enabled && payouts_enabled`; Tipalti: payable status) and sets `payable`/`onboardingStatus` from what the provider actually reports. One provider account can only ever fund **one** payee. An id already linked to a **different** payee is rejected `409` (without revealing who holds it). Re-adopting the SAME `(payee, provider, providerAccountId)` is a safe, idempotent replay. An account the rail can't confirm (nonexistent, on a foreign platform, or a failed live call) is rejected `422`. On a payable adoption the payee flips payable/verified and the same `payee.updated` webhook a normal onboarding completion fires is enqueued. **Required scope:** `payees:write`.
Check payout readiness GET
The **pull backstop**: can we pay this person right now, via which rail, and if not, what's blocking? Always correct even if a `payee.updated` webhook was missed. `blockers` is a list of machine-readable reasons (e.g. `kyc_incomplete`, `not_payable`). **Required scope:** `payees:read`.