Endpoint
Request a payout batch
/v1/payout_batchesVerified merchants only. Up to 200 rows, each a payout body. The whole batch is validated first: one bad row rejects the batch with errors[] naming each row. One approval covers the batch; how many transactions that is depends on the network (one Safe transaction per row on an EVM network, with at most 50 rows from one EVM network, one transaction with an output per row on Bitcoin, Litecoin and Dogecoin, one per row on TRON) and each row has its own state. Batch states are derived from the rows: awaiting_approval, then processing, then completed (all rows confirmed) | completed_with_failures or needs_attention (a row is unknown); plus cancelled, which is how the API shows a batch that was withdrawn or rejected.
- Scope a restricted key needs
payouts:write- Publishable key
- Not allowed: secret or restricted key only
- Idempotency-Key
- Required. A request without it is refused.
Parameters
| Parameter | Type and place | Meaning |
|---|---|---|
Orrerie-Version | stringheader | API version date. Default: the version the key was created with. Example 2026-10-11. |
Idempotency-Keyrequired | stringheader | Required here: a person at your business approves what this request asks for (money out, or a new saved address), and a retry with the same key never asks for it twice. 1 to 255 characters. |
Request body
A JSON object. The body is required. A field the call does not list is refused with parameter_unknown.
| Field | Type | Meaning |
|---|---|---|
description | string | Your description of the batch. |
rowsrequired | array of values | 1 to 200 payout bodies. |
metadata | object | Your own key-value data (rules in Metadata). |
Example request
curl
curl https://api.orrerie.com/v1/payout_batches \
-H "Authorization: Bearer $ORRERIE_SECRET_KEY" \
-H "Idempotency-Key: 8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a" \
-H "Content-Type: application/json" \
-d '{
"description": "October contractor payments",
"rows": [
{
"source": {
"asset": "base:usdc",
"amount": "900.00"
},
"destination": "dst_6rxm2vzjct7x9svh1vr4bsf3",
"reference": "C-01"
},
{
"source": {
"asset": "base:usdc",
"amount": "800.00"
},
"destination": "dst_d89z78ck9qnsqf23d63yrhs8",
"reference": "C-02"
}
]
}'JavaScript
const response = await fetch("https://api.orrerie.com/v1/payout_batches", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ORRERIE_SECRET_KEY}`,
"Idempotency-Key": "8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a",
"Content-Type": "application/json",
},
body: JSON.stringify({
"description": "October contractor payments",
"rows": [
{
"source": {
"asset": "base:usdc",
"amount": "900.00"
},
"destination": "dst_6rxm2vzjct7x9svh1vr4bsf3",
"reference": "C-01"
},
{
"source": {
"asset": "base:usdc",
"amount": "800.00"
},
"destination": "dst_d89z78ck9qnsqf23d63yrhs8",
"reference": "C-02"
}
]
}),
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
console.log(result);Python
import os
import requests
response = requests.post(
"https://api.orrerie.com/v1/payout_batches",
headers={"Authorization": f"Bearer {os.environ['ORRERIE_SECRET_KEY']}", "Idempotency-Key": "8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a"},
json={
"description": "October contractor payments",
"rows": [
{
"source": {
"asset": "base:usdc",
"amount": "900.00",
},
"destination": "dst_6rxm2vzjct7x9svh1vr4bsf3",
"reference": "C-01",
},
{
"source": {
"asset": "base:usdc",
"amount": "800.00",
},
"destination": "dst_d89z78ck9qnsqf23d63yrhs8",
"reference": "C-02",
},
],
},
timeout=30,
)
result = response.json()
if not response.ok:
raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
print(result)PHP
<?php
$request = curl_init('https://api.orrerie.com/v1/payout_batches');
curl_setopt_array($request, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ORRERIE_SECRET_KEY'),
'Idempotency-Key: 8f14e45f-ceea-467f-a9d2-6f1c2b3d4e5a',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'description' => 'October contractor payments',
'rows' => [
[
'source' => [
'asset' => 'base:usdc',
'amount' => '900.00',
],
'destination' => 'dst_6rxm2vzjct7x9svh1vr4bsf3',
'reference' => 'C-01',
],
[
'source' => [
'asset' => 'base:usdc',
'amount' => '800.00',
],
'destination' => 'dst_d89z78ck9qnsqf23d63yrhs8',
'reference' => 'C-02',
],
],
]),
]);
$body = curl_exec($request);
if ($body === false) {
throw new RuntimeException(curl_error($request));
}
$result = json_decode($body, true);
if (curl_getinfo($request, CURLINFO_HTTP_CODE) >= 400) {
throw new RuntimeException($result['error']['code'] . ': ' . $result['error']['message']);
}
print_r($result);Responses
202 Accepted
The request was accepted and is waiting: for a person to approve it in the dashboard, or to be built in the background. Nothing has been signed or sent. The answer is the payout_batch object. Headers: Orrerie-Request-Id.
Example response, 202
{
"id": "pob_b1xkj45rqwdaf7j2bc94pef3",
"object": "payout_batch",
"livemode": true,
"created": "2026-10-12T09:40:00.000Z",
"status": "awaiting_approval",
"description": "October contractor payments",
"row_count": 2,
"total_value": {
"amount": "1700.00",
"currency": "USD"
},
"counts": {
"draft": 0,
"awaiting_approval": 2,
"signed": 0,
"sent": 0,
"confirmed": 0,
"failed": 0,
"unknown": 0,
"cancelled": 0
},
"payouts": [
"po_crs9tp390f2yjremph9m0npb",
"po_kyrcy0h8t43wvedbxe5v40bp"
],
"requested_by": {
"type": "api_key",
"id": "key_6e3gg2c6ea176xxdek2nar6v"
},
"approved_by": null,
"approval_url": "https://merchant.orrerie.com/approve/pob_b1xkj45rqwdaf7j2bc94pef3",
"approval_expires_at": "2026-10-19T09:40:00.000Z",
"approved_at": null,
"completed_at": null,
"cancellation_reason": null,
"metadata": {}
}Any other status: an error
A status of 400 or above answers with the error object. Branch on its code, never on its message.
Errors
Beside the errors every call can answer with (a bad key, a missing scope, the rate limit), this call answers with:
| Code | HTTP | Meaning |
|---|---|---|
idempotency_key_required | 400 | The endpoint moves money on approval (refunds, payouts, batches, conversions, saved addresses) and needs an Idempotency-Key. |
insufficient_balance | 409 | The available balance (amount minus reserved) of the source asset is too low; error.available gives it. |
fee_account_low | 409 | The fee account cannot pay the network fee. error.needed says how much of which coin on which network must be held, for example {"asset": "tron:. |
saved_address_not_usable | 409 | The saved address is awaiting_approval, waiting (error.usable_at says until when) or removed. |
destination_blocked | 403 | The destination address is on a sanctions list. The request is refused and recorded. |
screening_unavailable | 503 | The sanctions check could not be made. A failed check is never treated as clean; retry later. |
merchant_restricted | 403 | The merchant is restricted: new orders, payouts to others and conversions are off. Reads and withdrawals to saved addresses work. |
payout_batch_not_allowed | 403 | Batches need the Verified tier. |
payout_batch_too_large | 400 | More than 200 rows, or more than 50 rows sent from one EVM network. |
payout_daily_limit_reached | 403 | Payouts to others in the last 24 hours (payouts, split legs and refunds to a saved address) plus this one would pass US$1,000 (Unverified) or US$100,000 (Verified). Withdrawals to own saved addresses have no tier limit. |
merchant_closing | 403 | The business is closing: new orders, payment links and invoices are off, and money goes out only to its own saved addresses. Reads, exports and withdrawals to saved addresses work until it closes. |
wallet_needs_review | 409 | The wallet holds less than Orrerie's records show, because money left it that nothing recorded. Money out from it waits until an Owner has reviewed the wallet in the dashboard. |