Passer au contenu

Crypto Mass Payout API: Automate Batch Payouts with a Reviewed Release Flow

A developer's guide to Payora's crypto mass payout API: the exact endpoints, HMAC request signing, idempotency, strict validation, webhooks, and why batch creation is not the same as confirmed on-chain payout.

Payora10 min readEN · RU · UK · ES · DE

What the crypto mass payout API actually does

A single POST /v1/payout call reserves the funds for the whole batch, validates every recipient, and creates a payout batch you can track. That is the honest shape of a crypto mass payout API on a gateway with an internal Payora balance: the API automates submission, validation, status and webhooks, while release follows the approval, signing or release flow configured for the account. A created batch is not the same thing as confirmed on-chain payout, and recipients should not be marked paid until status and transaction evidence prove it. If that trade-off sounds acceptable, the API turns a manual payroll or affiliate run into two or three lines of code.

This is a developer guide. It copies the exact contract from the API docs so you can ship against it today: the endpoints, the HMAC signing, the Idempotency-Key, the strict 422 validation, the payout.sent webhook, and how cancel releases the held balance. If you want the product overview first, read the mass payouts page.

Why submission and release are separate

When you submit a batch — from the cabinet or through the API — Payora reserves the total plus the per-item move fee on your internal balance, so the batch cannot be overspent. The batch then follows the approval, signing or release flow configured for the account. Treat this as a reviewed payout workflow, not as proof that money has already landed with every recipient.

The security model you want is simple: do not make "API call, coins instantly gone" your mental model unless that is explicitly the product you have chosen. Fully automatic hot-wallet-style payout products can be faster, but they also raise the blast radius of an account or server compromise. Payora's current operational steps should be checked in the product docs and account settings before you treat a batch as released.

Authentication and request signing

The crypto mass payout API uses the same auth as the rest of Payora. Every request carries three headers: X-Payora-Key, X-Payora-Timestamp (Unix seconds, ±120s skew), and X-Payora-Signature. The signature is an HMAC-SHA256 over the timestamp, a literal dot, and the exact raw request body:

X-Payora-Signature = hex(HMAC-SHA256(api_secret, timestamp + "." + raw_body))

Sign the bytes you actually send, before any reserialization. If your HTTP client re-encodes the JSON, capture the raw body first and hash that. This is the identical scheme used to verify inbound webhooks, covered in HMAC-SHA256 webhook signature verification.

POST /v1/payout: submit a batch

Send a currency, up to 500 items, and an optional note. Each item is an address, an amount as a string, and an optional tag — the XRP destination tag or XLM memo when the asset needs one.

curl -X POST https://api.payora.money/v1/payout \
  -H "X-Payora-Key: pk_live_9f3c8a12" \
  -H "X-Payora-Timestamp: 1753280400" \
  -H "X-Payora-Signature: 7b1e0c4d9a55f2..." \
  -H "Idempotency-Key: payroll-2026-07" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USDT",
    "items": [
      {"address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "amount": "250.00"},
      {"address": "TXk9mP2v7wQ3nR5tYb1cD8eF4gH6jK0lMn", "amount": "1800.00", "tag": ""}
    ],
    "note": "July contractors"
  }'

On success you get 201 with a batch you can track. The total is the sum of amounts, fee is the move fee of your plan (1.5% on Free) plus the coin’s network fee, and both are already held against your balance:

{
  "batch_id": "po_7Qd2K8xM4b",
  "status": "pending",
  "currency": "USDT",
  "item_count": 2,
  "total": "2050.00",
  "fee": "20.50",
  "items": [
    {"index": 0, "address": "TR7NHqjeKQ...", "amount": "250.00", "status": "pending"},
    {"index": 1, "address": "TXk9mP2v7w...", "amount": "1800.00", "status": "pending"}
  ]
}

Accepting payments is still 0%; the move fee only applies when money leaves. Network fees are separate and paid on-chain at broadcast time.

Strict validation: no silently dropped recipient

Validation is all-or-nothing on purpose. If any address is malformed for the chosen network, or any amount carries more decimal places than the coin supports, the entire batch is rejected with 422 and the offending indexes. Nothing is queued, nothing is held.

HTTP/1.1 422 Unprocessable Entity
{
  "error": "validation_failed",
  "invalid_items": [3, 17],
  "message": "invalid address at index 3; amount exceeds coin precision at index 17"
}

This is the behaviour you want for payroll. A gateway that quietly truncated 1800.123456789 or skipped one bad row would underpay or drop a person, and you would not notice until someone complained. Fix the flagged indexes and resubmit the whole batch.

Idempotency: retries never double-pay

Networks time out. A payout request that fails midway is dangerous to retry blindly, so send an Idempotency-Key header — any stable, unique string for that logical batch (a payroll period, an invoice group). If a request with the same key arrives again, Payora returns the original batch instead of creating a second one. Reuse the key for every retry of the same batch; use a fresh key for a genuinely new batch.

  • Same key, same batch — safe to retry after a timeout; you get the first result back.
  • New key — a new batch, a new hold on your balance.
  • Store the returned batch_id as soon as you have it, so you can reconcile even if the response was lost.

Reconcile with GET /v1/payout/{id}

After the configured release flow advances, poll GET /v1/payout/{id} for the current status and a per-item tx_hash when transaction evidence is available. GET /v1/payout lists recent batches for dashboards and audits. Store the batch_id and each item index against your own records so every recipient maps to evidence you can show them.

Need to pull one back before release? POST /v1/payout/{id}/cancel cancels a still-pending batch and releases the held balance in full. Once items are released on-chain they are final, like any crypto transaction — cancel only works while the batch is pending.

The payout.sent webhook

Rather than polling forever, subscribe to payout.sent. After the configured release flow completes and Payora has transaction evidence for the batch items, Payora fires a signed webhook using the same HMAC signing as invoice.paid. Verify it the same way — recompute the signature over timestamp, dot, raw body and compare in constant time:

$expected = hash_hmac('sha256', $timestamp . '.' . $raw_body, $webhook_secret);
if (!hash_equals($expected, $signature_header)) { http_response_code(400); exit; }
// payload.event == "payout.sent", payload.batch_id, payload.items[].tx_hash

Only after that check passes should you mark the payroll run complete, email receipts, or update ledgers. An unverified webhook is just an untrusted HTTP request.

A minimal integration checklist

  1. Create an account and generate API keys at register; fund the internal balance in the currency you will pay out.
  2. Build the raw JSON body, sign it (timestamp + "." + body) with HMAC-SHA256, attach the three headers plus an Idempotency-Key.
  3. POST /v1/payout; on 201 persist the batch_id, on 422 fix the flagged indexes and resend.
  4. Complete the approval, signing or release steps configured for the account.
  5. Verify the payout.sent webhook, or poll GET /v1/payout/{id}, and record each tx_hash.

That is the whole loop. The API removes the tedious, error-prone part — building, validating and tracking a 500-line batch — while your operational controls decide when a reviewed batch is actually released.

Start building

Read the Mass Payout API section of the docs, grab keys at register, and see the feature end to end on the mass payouts page. You can automate batch creation today and keep payout release tied to the controls configured for your account.

Comments

Ready to get started?

Create an account and have your first invoice running in under an hour.

Ce que cette page répond