Create a payout
Sends stablecoin from your API account to an external address. Knit checks the balance, holds the amount, and submits the transfer.
Before you call
- The API account must exist and be funded.
Create it for the token you are paying
out, then fund it from the dashboard or let collections credit it. A short
balance is rejected with
400, and nothing is held. - Your server IP must be allow-listed. Requests from other addresses are rejected before reaching this endpoint.
- The destination address must be valid for the network. Addresses are
checked per chain; a malformed or wrong-chain address fails with
400.
Supported networks
| Network | Identifier |
|---|---|
| Polygon | MATIC_MAINNET |
| Tron | TRON_MAINNET |
| BNB Smart Chain | BSC_MAINNET |
| Solana | SOL_MAINNET |
Payout availability is narrower than collection availability — a network that
accepts collections may not support payouts. Check payoutStatus in
GET /api/v1/networks before you build
against a chain.
Body
One of the payout networks above.
USDT or USDC.
The amount to send, in token units — not fiat. Minimum 0.01.
The destination address. Validated against the format and checksum rules of the chosen network.
Your own reference for this payout. Must be unique across your payouts — this is what makes retries safe.
merchantReference is required, not optional. Generate it from something
stable on your side — an invoice ID, a ledger entry ID — so that replaying a
request whose outcome you are unsure of is rejected as a duplicate rather
than sending the money twice.
Request
curl -X POST "https://api-prod.useknit.io/api/v1/payouts" \
-H "Authorization: Bearer $KNIT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"network": "MATIC_MAINNET",
"token": "USDT",
"amount": 25.5,
"toAddress": "0x56adfcc254ab3b8142a275c1837bcffaff5aa38b",
"merchantReference": "INV-2045"
}'Response
Returns 201. The payout starts at PENDING — it has not settled on-chain
yet.
{
"statusCode": 201,
"message": "Payout created successfully",
"data": {
"id": "8e5697e3-8265-455b-984a-0eb40e10b0f9",
"businessId": "b7b93a40-4e18-4e97-9c5f-8a7a4fd0df92",
"network": "MATIC_MAINNET",
"token": "USDT",
"amount": "25.500000000000000000",
"toAddress": "0x56adfcc254ab3b8142a275c1837bcffaff5aa38b",
"merchantReference": "INV-2045",
"transactionHash": null,
"status": "PENDING",
"info": null,
"createdAt": "2024-08-27T13:44:20.000000Z",
"updatedAt": "2024-08-27T13:44:20.000000Z"
},
"success": true
}Status lifecycle
| Status | Meaning |
|---|---|
PENDING | Accepted and queued. The balance has been held |
PROCESSING | Submitted for settlement; awaiting on-chain confirmation |
COMPLETED | Confirmed on-chain. transactionHash is populated and a PAYOUT_SUCCESSFUL webhook is delivered |
FAILED | Could not be settled. Check info for the reason |
A failed payout is not retried automatically at the same merchantReference.
To try again, submit a new payout with a new merchantReference once you
have resolved the cause.
Track completion with the PAYOUT_SUCCESSFUL webhook
rather than polling. If you need to check state on demand — reconciling after an
outage, say — use Retrieve a payout or
Get payout status.
Errors
| Status | Cause |
|---|---|
400 | A field failed validation: amount below 0.01, an unsupported network, an invalid toAddress, or a merchantReference you have already used |
400 | Insufficient balance in the API account for that token, or the payout could not be accepted |
401 | Missing or invalid token, IP not allow-listed, or missing payouts:write |
404 | Wallet not found for the specified token — no API account exists for that token yet |
Both cases are 400, but the bodies differ. A validation failure carries an
errors object naming the offending fields:
{
"message": "The merchant reference has already been taken.",
"errors": {
"merchantReference": ["The merchant reference has already been taken."]
}
}A rejected-but-valid request carries the standard envelope and no errors:
{
"statusCode": 400,
"message": "Insufficient balance",
"data": null,
"success": false
}Branch on the presence of errors to tell them apart — see
Requests & responses.