POST

Create Payout Multiple

La referencia de la API está en inglés. Las guías, la autenticación, los webhooks y los códigos de error están en español.

Creates up to 50 payouts in one request.

Send an array of payout objects with the same fields as Create Payout Single. Items are processed one by one, each in its own transaction: a refused item is reported on its own index and the rest of the batch still goes out. The HTTP status is 200 when every item was created, 207 when some were created and some refused, and 400 when every item was refused; in all three cases the body carries summary and one entry per item in results, in the order sent. If every item fails validation, the answer is instead a top-level invalid_parameters with no results. More than 50 items returns 400 max_payouts_exceeded and nothing is processed.

POSThttps://bridge.bifrostcrypto.com/v1/payout
Alcance requerido:payout:write(una clave nueva sin lista es de solo lectura)
ᚱ
"En la forja de Heimdall, múltiples pagos se tejen juntos como los hilos del destino. Cada transacción lleva la fuerza combinada de Mjolnir y fluye como un río unificado por los reinos."
Brokkr & Sindri, Forjadores Divinos

Headers

KeyValue
X-Bifrost-Invoke{{api_key}}
Content-Typeapplication/json
Idempotency-Key{{uuid}}

Request Body

json
[
  {
    "wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
    "crypto_currency": "USDT",
    "fiat_currency": "USD",
    "crypto_amount": "100.50",
    "process_by": "crypto_amount",
    "reference_id": "order_12345",
    "network": "Ethereum",
    "feetakenfromamount": 0,
    "webhook_url": "https://your-site.com/webhook",
    "customer_info": "customer123"
  },
  {
    "wallet": "0x8Ba1f109551bD432803012645Ac136ddd64DBA72",
    "crypto_currency": "BNB",
    "crypto_amount": "0.5",
    "process_by": "crypto_amount",
    "reference_id": "order_12346",
    "network": "BinanceSmartChain",
    "feetakenfromamount": 1,
    "webhook_url": "https://your-site.com/webhook"
  }
]

cURL Example

bash
curl -X POST "https://bridge.bifrostcrypto.com/v1/payout" \
  -H "X-Bifrost-Invoke: YOUR_API_KEY" \
  -H "Idempotency-Key: 3f1c8b2a-9d54-4f6e-8c31-7b0a2e5d9411" \
  -H "Content-Type: application/json" \
  -d '[
  {
    "wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
    "crypto_currency": "USDT",
    "fiat_currency": "USD",
    "crypto_amount": "100.50",
    "process_by": "crypto_amount",
    "reference_id": "order_12345",
    "network": "Ethereum",
    "feetakenfromamount": 0,
    "webhook_url": "https://your-site.com/webhook",
    "customer_info": "customer123"
  },
  {
    "wallet": "0x8Ba1f109551bD432803012645Ac136ddd64DBA72",
    "crypto_currency": "BNB",
    "crypto_amount": "0.5",
    "process_by": "crypto_amount",
    "reference_id": "order_12346",
    "network": "BinanceSmartChain",
    "feetakenfromamount": 1,
    "webhook_url": "https://your-site.com/webhook"
  }
]'

Response Example

json
{
  "message": "payment_processing_completed",
  "summary": {
    "total_requested": 2,
    "successful": 2,
    "failed": 0
  },
  "results": [
    {
      "index": 0,
      "reference_id": "order_12345",
      "internal_reference": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "crypto_amount": "100.5",
      "fiat_amount": "100.50000000",
      "crypto_currency": "USDT",
      "fiat_currency": "USD",
      "network_fee": "0.00100000",
      "wallet": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
      "memo": null,
      "network": "Ethereum",
      "process_by": "crypto_amount",
      "status": "created"
    },
    {
      "index": 1,
      "reference_id": "order_12346",
      "internal_reference": "9b2e4c1a-7d3f-4e8b-a1c6-5f0d2e9b7a43",
      "crypto_amount": "0.4924",
      "fiat_amount": "300.00000000",
      "crypto_currency": "BNB",
      "fiat_currency": "USD",
      "network_fee": "0.00010000",
      "wallet": "0x8Ba1f109551bD432803012645Ac136ddd64DBA72",
      "memo": null,
      "network": "BinanceSmartChain",
      "process_by": "crypto_amount",
      "status": "created"
    }
  ]
}

Network aliases

On create, network also accepts these aliases. Case, spaces, hyphens and underscores are ignored (ERC-20, erc_20 and erc20 are the same). Responses, webhooks and listings always return the canonical name. bnb means BinanceSmartChain (for opBNB send OpBnb) and arb means Arbitrum (for ArbitrumOne send ArbitrumOne).

NetworkAliases
Ethereumeth, eth-mainnet, erc20
Trontrx, trc20
BinanceSmartChainbnb, bsc, bep20, bnbchain, bnb-smart-chain
Arbitrumarb, arbitrum-evm
Polygonmatic, pol, polygon-pos
Optimismop, op-mainnet
Avalancheavax, avaxc, avalanche-c
Solanasol
Bitcoinbtc
Litecoinltc
Moneroxmr
Xlayerokb

Item refusal codes

Codes an entry can carry in results[].error.code. The rest of the batch continues and nothing is debited for the refused item. Codes marked No in reference_id come back without it: match those items by index.

CodeWhenreference_idWhat to do
invalid_parametersA field failed validation; details.fields names it.YesFix the field and resend the item.
duplicate_payment_referencereference_id was already used by an earlier payout.YesUse a new reference_id, or check the earlier payout with GET /v1/list-payout.
duplicate_reference_id_in_requestTwo items of the same request share a reference_id.NoGive each item its own reference_id.
invalid_crypto_amount · invalid_fiat_amount · fiat_currency_requiredThe amount or currency required by process_by is missing or invalid.NoFix the item and resend it.
invalid_network_or_withdrawals_disabled · unsupported_token_or_withdrawals_disabled · token_network_mismatchThe token or network does not accept withdrawals for your account.NoChoose another token or network (GET /v1/summary/tokens).
token_not_activeThe token is not active.YesChoose another token.
memo_requiredThe token needs a memo.NoSend memo.
invalid_formatThe address does not match the network.YesCheck the address and network.
limit_exceededBelow the token minimum after fees, or above the maximum.YesAdjust the amount.
amount_does_not_cover_feesWith feetakenfromamount = 1, fees consume the whole amount.YesIncrease the amount.
insufficient_balanceThe balance does not cover the item and its fees.YesTop up the balance.
daily_payout_limit_exceededThe key's daily payout limit (USD, UTC day) would be exceeded.YesWait for the next UTC day or ask for a higher limit.
price_unavailable · daily_payout_limit_unavailableA quote needed for the item was not available.YesRetry the item later.
error_fetching_active_tokensThe token catalogue could not be loaded.NoRetry the item later.
database_error · internal_errorFailure on our side.YesRetry the item later.
record_not_found · user_not_foundThe account setup is incomplete.YesContact support.

Errors

Every error has the shape error.code, error.message and, when useful, error.details. Authentication, scope and rate-limit errors (401, 403, 429) apply to every endpoint and are described under Authentication.

StatusCodeWhenWhat to do
400json_parse_exception · json_parse_failedThe body is missing or is not valid JSON.Fix the request before sending it again.
400invalid_payment_listThe body is neither a payout object nor a non-empty list.Fix the request before sending it again.
400max_payouts_exceededMore than 50 payouts in one request.Split into requests of up to 50.
400invalid_parametersEvery item failed validation; details.fields is keyed by index.field.Fix the request before sending it again.
400insufficient_total_balanceThe items of one currency add up to more than the available balance. Nothing is debited.Top up the balance or send fewer payouts.
200 · 207 · 400results[].error.codeAn item was refused after validation (see the Item refusal codes table).Fix and resend only the refused items, with a new Idempotency-Key.
404user_not_found · record_not_foundThe account setup is incomplete.Contact support.
409idempotency_key_in_progressA request with this Idempotency-Key is still running.Wait and retry with the same key.
500error_fetching_active_currenciesThe token catalogue could not be loaded. Nothing was processed.Nothing was changed. Retry later.
500internal_errorUnexpected failure; summary and results show what was created.Resend only the items counted in summary.not_processed.

Otras respuestas

Respuestas que no son el camino feliz y aun así necesitan tratamiento en su integración.

207

Partial success

Returned when at least one item was created and at least one was refused; when every item is refused the same body comes with 400. Every entry in results carries its index, so you can match a failure back to the object you sent; a refused entry has error with code and message, and an item that failed validation lists the reason per field in error.details.fields. A reference_id already used by an earlier payout comes back with duplicate: true, the original payout's internal_reference, its current status (pending, completed, failed or refunded) and its creation time, and no second transfer is made. The same reference_id twice in one request is refused on the later index with duplicate_reference_id_in_request. Created entries carry the full fields shown in the 200 example (shortened here).

json
{
  "message": "payment_processing_completed",
  "summary": {
    "total_requested": 5,
    "successful": 2,
    "failed": 3
  },
  "results": [
    {
      "index": 0,
      "reference_id": "order_12345",
      "internal_reference": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "status": "created"
    },
    {
      "index": 1,
      "reference_id": "order_12346",
      "error": {
        "code": "invalid_parameters",
        "message": "Invalid parameters provided",
        "details": {
          "fields": {
            "crypto_amount": "Crypto amount must be a positive decimal number"
          }
        }
      }
    },
    {
      "index": 2,
      "reference_id": "order_12347",
      "internal_reference": "3c9d1e7f-2a4b-4f6c-8e0d-b5a7c3f1e902",
      "status": "created"
    },
    {
      "index": 3,
      "reference_id": "order_11999",
      "internal_reference": "6e1b8f2d-4c7a-4d9e-b3f0-a2c5e8d1f764",
      "duplicate": true,
      "original_status": "pending",
      "original_created_at": "2026-01-16 10:00:00",
      "error": {
        "code": "duplicate_payment_reference",
        "message": "A payout with this reference_id already exists"
      }
    },
    {
      "index": 4,
      "error": {
        "code": "duplicate_reference_id_in_request",
        "message": "This reference_id appears more than once in the request"
      }
    }
  ]
}
400

Every item invalid

When every item fails validation nothing is processed and there are no results: the reasons come at the top level, in details.fields keyed by index.field. An entry that is not a JSON object is reported as index.item.

json
{
  "error": {
    "code": "invalid_parameters",
    "message": "Invalid parameters provided",
    "details": {
      "fields": {
        "0.webhook_url": "Webhook URL is required",
        "1.crypto_currency": "Invalid crypto currency"
      }
    }
  }
}
400 / 404 / 500

Request-level errors

Nothing is processed. The codes are listed in the Errors table.

json
{
  "error": {
    "code": "max_payouts_exceeded",
    "message": "Too many payouts in a single request"
  }
}
409

Idempotency-Key still running

The first request with this key has not finished yet. Wait and retry with the same key; do not send the batch again without it. After 15 minutes without an answer the key is freed and the next request with it is processed.

json
{
  "error": {
    "code": "idempotency_key_in_progress",
    "message": "A request with this Idempotency-Key is still being processed"
  }
}
400

Not enough balance for the batch

Checked before anything is debited. Valid items of the same currency are summed using the amount selected by process_by (fees not included), and compared with the available balance after holds. Nothing is created. Fees are checked per item afterwards, so an item can still be refused with insufficient_balance.

json
{
  "error": {
    "code": "insufficient_total_balance",
    "message": "Insufficient balance to cover all payouts",
    "details": {
      "crypto_currency": "USDT",
      "available": "150.00000000",
      "required": "420.500000000000000000"
    }
  }
}
207 / 400 (item)

Item refusal codes

Returned on the refused entry; the rest of the batch continues and nothing is debited for it. Every code, and whether it carries reference_id, is in the Item refusal codes table.

json
{
  "index": 2,
  "reference_id": "order_12347",
  "error": {
    "code": "limit_exceeded",
    "message": "Amount is outside the allowed limits"
  }
}
207 / 400 (item)

Daily payout limit reached

Only when the key has a daily payout limit configured (in USD). Each payout counts its total debit converted to USD, and the limit covers the UTC calendar day (00:00 to 23:59 UTC), unlike the other dates of the API, which are in UTC−03:00. The item is refused on its index; the rest of the batch continues.

json
{
  "index": 3,
  "reference_id": "order_12348",
  "error": {
    "code": "daily_payout_limit_exceeded",
    "message": "Daily payout limit for this API key exceeded"
  }
}
207 / 400 (item)

Amount does not cover fees

Only with feetakenfromamount = 1: fees consume the whole amount, so the recipient would receive nothing. The item is refused on its index; the rest of the batch continues.

json
{
  "index": 1,
  "reference_id": "order_12346",
  "error": {
    "code": "amount_does_not_cover_fees",
    "message": "Amount does not cover the fees"
  }
}
207 / 400 (item)

Daily limit cannot be accounted

Only when the key has a daily limit configured and the spend record could not be written. The item is refused on its index; the rest of the batch continues. Safe to resend later with the same reference_id.

json
{
  "index": 3,
  "reference_id": "order_12348",
  "error": {
    "code": "daily_payout_limit_unavailable",
    "message": "Daily payout limit could not be checked right now"
  }
}
207 / 400 (item)

Price unavailable

Returned on the item when a conversion price is missing (fiat_amount conversion, or the network fee converted into the token), and also when the key has a daily limit but the token has no USD quote to count the payout. The rest of the batch continues.

json
{
  "index": 2,
  "reference_id": "order_12347",
  "error": {
    "code": "price_unavailable",
    "message": "Price information temporarily unavailable"
  }
}
500

Interrupted mid-batch

An unexpected failure stops the loop, but the items already created are returned: summary and results stay at the top level next to error. not_processed tells you how many never got that far, so you can resend only those, and the uniqueness of reference_id still protects you if you resend more than you should. The Idempotency-Key is not stored for this response.

json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred during payment processing"
  },
  "summary": {
    "total_requested": 50,
    "successful": 31,
    "failed": 1,
    "not_processed": 18
  },
  "results": [
    "..."
  ]
}