Skip to content

How payouts work ​

Who moves the money, what Zay checks, and how a payout ends.

Do it: Get started · Look it up: Payouts, Payout events

You send, Zay confirms ​

A payout represents a USDC transfer to a user. You send the transfer on-chain yourself, to the user's wallet_address, then report it, passing the transaction_hash. The payout is created in pending.

Zay then looks for the matching USDC deposit in the user's wallet — same transaction hash, same amount. When it finds one, the payout moves to received and Zay sends payout.received. You never report the outcome yourself.

Pay a user only after user.onboarding_completed — see How onboarding works. Zay does not stop you from reporting a payout earlier, but there is no wallet to confirm it against.

The lifecycle ​

pending ──matching deposit found──────────────→ received
   └─────deposit mismatched, or none in 48 hours──→ expired
  • pending — reported, not yet confirmed.
  • received — terminal success. Zay confirmed the transfer and sent payout.received.
  • expired — terminal failure. Either the deposit did not match the report (wrong amount, token, or a failed transaction), or no matching deposit arrived within 48 hours. Zay sent payout.expired, with the cause in reason.

received and expired are final — a payout never leaves them.

Confirmation is not live yet ​

Zay does not yet confirm deposits to the user's wallet, on staging or in production. Until it does, every reported payout stays pending and moves to expired after 48 hours, with payout.expired and the reason deposit not confirmed within the verification window. The lifecycle above is the contract you integrate against; only the received branch is not reachable yet.