Link released disbursements to their replacement payout
Attach several already-released owed rows to ONE already-submitted replacement payout. A ledger repair only: it never creates, retries, or calls a payout provider — it repairs the pre-consolidation fan-out shape, where a withdrawal released N disbursements as N one-row payouts and a single replacement payout was later submitted in their place.
Idempotent — re-sending the same (replacementTransactionId, disbursementIds) returns idempotentReplay: true and links nothing twice.
The replacement's amount must equal the sum of the linked rows, and every row
must belong to the replacement's payee, or the call is rejected whole.
Required scope: disbursements: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
// The SDK has no helper for this endpoint yet. Use the cURL tab, or// call it with any HTTP client: the SDK's request signing scheme is// documented under Authorization on this page.{ "linked": 0, "idempotentReplay": true}Push owed (IOU) rows POST
Push owed (IOU) rows programmatically — the API twin of the client-portal CSV upload. Each item identifies the payee by EXACTLY ONE of `payeeId` (one you own) or `email` (resolve-or-create, mirroring `BatchPayoutItem`), plus an `amountCents` and YOUR stable `externalRef` (e.g. your ledger row id). The response is **`207 Multi-Status`** with one entry per row, in request order: `status: ok` carries the created (or replayed) `disbursement`, `status: error` carries a stable `error` code from the closed per-row enum on `DisbursementPushResultItem.error`. A failing row **never** aborts the others. **Idempotent per row** on `(yourClient, externalRef)` — pushing the same `externalRef` again always returns the SAME owed row (`idempotentReplay: true`) rather than double-crediting, regardless of its current status, and a replay never re-touches payee data. Two rows in the SAME call sharing an `externalRef` is always a caller bug (an owed row's ledger id is unique by definition) and is rejected as a whole-request `400 duplicate_external_ref` before any row is processed. Set `sendEmail: true` to send the "you have money waiting" email — sent only for rows that were newly **created** in this call, after the batch commits. Unlike `POST /payouts/batch`, the email resolve-or-create path here is authorized by `disbursements:write` alone — no separate `payees:write` is required. **Required scope:** `disbursements:write`.
payee.updated Webhook
Fired when a payee's onboarding state changes — typically when they finish onboarding and become **payable**. Map it back to your own record via `externalId`. (Tipalti payability is discovered by the gateway's reconcile polling, so this can arrive shortly after the payee finishes, not instantly.) You subscribe to specific event types when your client is provisioned. An event type you are not subscribed to is recorded but never delivered. **Signature.** The gateway POSTs to your registered webhook URL with `x-8x-timestamp` and `x-8x-signature` headers, where the signature is `HMAC-SHA256(signingSecret, "{timestamp}.{rawBody}")`, hex-encoded — the same scheme as outbound API requests. Verify before trusting the body (`PayoutClient.verifyWebhook` does this). Reject deliveries whose `x-8x-timestamp` is more than 5 minutes (300s) from now — `verifyWebhook` enforces this. Return any `2xx` to acknowledge; non-2xx (or a timeout) triggers retry with exponential backoff.