Skip to main content
Reuse the same payout ID when retrying a create request. This prevents a timeout or network error from causing your retry to create a second payout.

Supply your own payout ID

create accepts an optional id — a client-generated ID the new payout is created under. It must be a UUID (the API validates this); if omitted, the server generates one. For idempotency, don’t use a random UUID per attempt — derive a deterministic UUID (v5) from the thing that makes the payout unique in your system, such as an invoice ID or payroll period, so every retry produces the same id:
createFinalized requires a payout id. Reuse that ID on retries so you can look up the payout if the original response is lost.

Create a local payout run first

For automated payout runs that add payees to a funded pool or escrow, create a local payout-run record before calling Pvium. Store a durable UUID on that local record, then pass it as finalizeOptions.id when you call addPayments. That UUID becomes the linked scheduled child payout ID in Pvium. If the request succeeds but your worker times out before it sees the response, retry with the same local record and the same finalizeOptions.id instead of generating a fresh payout.
The API uses that id as the payout batch primary key. A duplicate retry will not create a second child payout, but it also will not replay the original response. Treat the duplicate or ambiguous error as a recovery path: fetch pvium.payout.get(id), verify it belongs to the expected parent pool or escrow, then mark your local run complete.

Individual payments

Within a batch, a payment’s identity is (batch, receiver, memo) — enforced by a unique constraint.
  • The same receiver can appear on multiple rows in one batch as long as each row carries a distinct memo. Put your per-payment business key in the memo — an invoice code or installment identifier like INV-1042:install-3 — and each obligation becomes its own idempotent row.
  • Re-adding the same (receiver, memo) never creates a second payment: a direct add is rejected as a duplicate, and an invite-driven attach updates the existing row’s amount in place.
  • A retried add-payments call therefore cannot double-pay anyone — the repeated rows collide on (batch, receiver, memo) instead of duplicating.

Nonces

Every payout also carries a nonce. The SDK generates one automatically; pass your own only if you need the nonce to be deterministic across systems.

Retry pattern

  1. Compute the payout id from your business key before calling Pvium.
  2. On a timeout or network error, retry the same call with the same id.
  3. A retried create whose id already exists is rejected as a duplicate — it will not create a second payout, and it will not return the existing one. Catch the conflict, fetch the payout with pvium.payout.get(id), and continue from its current state — it may already be created or even finalized.
  4. Key webhook processing on payout and payment IDs, so re-deliveries are no-ops. See Webhooks.

What finalization adds

Finalization is naturally idempotent in effect: it signs the payout’s exact contents, and funding accepts only that signed payout. Even if your retry logic misfires at the create step, nothing can be paid twice from one funding — the checkout funds the signed payment set, once.