Contractor payouts
Pay contractors in stablecoins by giving each one a dedicated USD account that converts and delivers automatically.
Your customers are the people getting paid. Each one is verified once, gets a dedicated USD bank account, and receives stablecoins whenever the payer sends money to it.
The shape
Build order
| Step | Call | Notes |
|---|---|---|
| 1. Onboard the contractor | POST /api/customers with kind: "individual" and endorsements: ["endo_usd"] | Requesting endo_usd needs email, phone, and the two economic_profile tax fields in the same request |
| 2. Submit for verification | POST /api/customers/{id}/verifications/submit | The only call that starts a review. Documents are staged before it |
| 3. Create their wallet | POST /api/customers/{id}/wallets | Needs approved verification, an approved endorsement, and your registered keys |
| 4. Create their account | POST /api/customers/{id}/virtual_accounts with a wallet destination | {"kind": "wallet", "asset": "usdc", "wallet_id": "wal_..."} |
| 5. Show the deposit details | deposit_instructions from step 4 | Give them to the payer verbatim |
| 6. Let them cash out | POST /api/wallets/{id}/operations, then authorize | See Sending Funds |
Steps 3 and 4 are in that order deliberately: a wallet destination needs
the wallet to exist first.
Why a wallet destination rather than an address
You could deliver straight to an address the contractor gives you, and for a one-off payout that is simpler. A held wallet earns its complexity when you want to:
- show a balance in your product, read from the chain rather than tracked by you;
- show history at
GET /api/wallets/{id}/history, including money the contractor received from anywhere else; - let them send without leaving your app.
If none of those apply, use {"kind": "address", ...} and skip the wallet
work entirely.
What to watch
endorsement.request_for_informationis the event your support load lives in. Contractors submit bad selfies. Build the fix-it screen from the requirement buckets before launch. See Verification needs more information.deposit.receivedtells you the payer paid.payout.completedcarries thetx_hashworth showing the contractor.wallet.deposit_receivedfires for money that arrived at the address without any payer of yours being involved. Contractors do get paid from elsewhere, and your ledger should not be surprised by it.
Fees
Set partner_fee_bps per account, so you can price contractors
differently: a flat percentage on each deposit, credited to your balance
in real time. Our own conversion fee is metered to your monthly invoice on
the standard plan, so the contractor's delivery goes out whole. See
Fees & Quotes.
The failure you should design for
A payer sends money before the contractor's verification is approved. The
account does not exist yet, so there is nothing to send to. Handle it in
product terms: do not publish deposit instructions until
endorsement.approved has fired, and tell the payer the contractor is
still onboarding rather than letting a wire bounce.