/api/v1/businesses/:id/payout-api-keysDashboard UI onlySandbox + liveCreate payout API key
Create a dedicated payout API key with allowlisted or dynamic destinations within configured limits.
When to use it
Use when a backend needs programmatic withdrawals after you have defined destination policy, token, network, spend, and optional IP guardrails.
| Field | Location | Required | Description | Example / default |
|---|---|---|---|---|
| id | path | Yes | Business ID. | - |
| name | body | Yes | Operator label for this payout key. | - |
| destinationPolicy | body | No | `allowlist` by default. Set to `any` to allow withdrawals to any valid destination while still enforcing token, network, spend, and optional IP limits. | - |
| destinations | body | No | Allowed withdrawal destinations, each with `chain`, `address`, and optional `label`. Required when `destinationPolicy` is `allowlist`. | - |
| limits | body | Yes | Allowed `chain`, `networkId`, `token`, `maxAmount` per withdrawal, and rolling `dailyAmount`. | - |
| ipAllowlist | body | No | Optional IPv4 addresses or CIDR blocks that may use this key. | - |
| expiresIn | body | No | Optional key lifetime in days, max 365. | - |
Cautions
- Payout keys cannot create dashboard sessions, manage API keys, or bypass the configured payout policy.
- `destinationPolicy: any` increases payout-key blast radius; use lower limits, shorter expiry, and IP allowlists when possible.
- The withdrawal request still needs an `Idempotency-Key`; policy approval is not a settlement guarantee.
- Rotate payout keys separately from standard API keys because the blast radius and alerting profile are different.
Common errors
- 401: Missing or invalid API key.
- 403: The caller is missing the required permission or auth mode for this action.
- 400: Payload shape, query params, or business-state validation failed.
Sample request body
json{
"name": "Vendor payouts",
"expiresIn": 30,
"destinationPolicy": "allowlist",
"destinations": [
{
"chain": "sol",
"address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp",
"label": "Solana operations wallet"
},
{
"chain": "eth",
"address": "0x5fBDB2315678afecb367f032d93F642f64180aa3",
"label": "Base operations wallet"
}
],
"limits": [
{
"chain": "sol",
"networkId": "sol-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
},
{
"chain": "eth",
"networkId": "base-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
}
],
"ipAllowlist": ["203.0.113.10/32"]
}Sample response
json{
"id": "key_payout_123",
"name": "Vendor payouts",
"kind": "payout",
"apiKey": "biz_live_payout_1234567890abcdef",
"permissions": ["payouts:create", "payouts:read"],
"expiresAt": "2026-04-11T15:35:00.000Z",
"createdAt": "2026-03-12T15:35:00.000Z",
"policy": {
"destinationPolicy": "allowlist",
"destinations": [
{
"chain": "sol",
"address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp",
"label": "Solana operations wallet"
}
],
"allowedChains": ["sol", "eth"],
"allowedNetworkIds": ["sol-mainnet", "base-mainnet"],
"allowedTokens": ["USDC"],
"limits": [
{
"chain": "sol",
"networkId": "sol-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
}
],
"ipAllowlist": ["203.0.113.10/32"]
},
"warning": "Store this payout API key securely. It can create withdrawals only within the configured policy and cannot be recovered."
}cURL example
bashcurl -X POST "https://api.paychainhq.io/api/v1/businesses/biz_123/payout-api-keys" \
-H "Content-Type: application/json" \
-d '{
"name": "Vendor payouts",
"expiresIn": 30,
"destinationPolicy": "allowlist",
"destinations": [
{
"chain": "sol",
"address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp",
"label": "Solana operations wallet"
},
{
"chain": "eth",
"address": "0x5fBDB2315678afecb367f032d93F642f64180aa3",
"label": "Base operations wallet"
}
],
"limits": [
{
"chain": "sol",
"networkId": "sol-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
},
{
"chain": "eth",
"networkId": "base-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
}
],
"ipAllowlist": ["203.0.113.10/32"]
}'Node.js example
tsconst response = await fetch('https://api.paychainhq.io/api/v1/businesses/biz_123/payout-api-keys', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Vendor payouts",
"expiresIn": 30,
"destinationPolicy": "allowlist",
"destinations": [
{
"chain": "sol",
"address": "8gRLe6GiQx2jo9mQFcbwy34u2W4zD2rN5q4mmD8iP2Mp",
"label": "Solana operations wallet"
},
{
"chain": "eth",
"address": "0x5fBDB2315678afecb367f032d93F642f64180aa3",
"label": "Base operations wallet"
}
],
"limits": [
{
"chain": "sol",
"networkId": "sol-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
},
{
"chain": "eth",
"networkId": "base-mainnet",
"token": "USDC",
"maxAmount": "1000",
"dailyAmount": "5000"
}
],
"ipAllowlist": ["203.0.113.10/32"]
}),
});
const payload = await response.json();
console.log(payload);