The Bulk Transaction API enables you to process multiple transactions within a single request. It offers two processing options: atomic processing, where all transactions either succeed or fail as a unit, and independent processing, where each transaction is handled separately.Additionally, the API supports asynchronous processing to efficiently manage large batches of transactions.
When true, either all transactions succeed or all fail. When false, transactions are processed independently.
inflight
When true, transactions are created in INFLIGHT status and require a separate commit. When false, transactions are processed immediately.
run_async
When true, processing happens in the background and results are delivered via webhook. When false or not provided, processing happens synchronously and results are returned in the response.
skip_queue
Defaults to false. When true, transactions bypass the queue and are processed inline in the request. Affects duplicate-reference handling — see Duplicate references.
transactions
Array of transaction objects. Max of 10,000 transactions per request.
Blnk returns a batch_id that identifies the batch. When skip_queue: false, Blnk stores batch_id as the queued parent transaction.Save it. You can use the same ID to retrieve, commit, refund, or void every transaction in the batch without tracking individual child IDs first. See Retrieving transactions in a batch.
On the default queued path, status: "applied" means the bulk request was successfully submitted, not that every child is already APPLIED on balances. Blnk enqueues each item for asynchronous processing.
When run_async is true, Blnk accepts the batch and returns immediately with status: "processing".Processing continues in the background. The HTTP response does not wait for each transaction to finish.Once done, Blnk sends one of the following webhook events with the final outcome.
To create inflight bulk transactions, set inflight: true in the request body. Blnk ignores any inflight flag passed in the transaction objects and respects the root inflight flag.When set, all transactions in the batch will be processed as INFLIGHT.To commit or void all inflight transactions in a batch, use the batch_id. For independently-created inflight holds, see Bulk commit & void.
{ "event": "bulk_transaction.failed", "data": { "batch_id": "bulk_4192d961-5b0e-46ca-bf2f-9386763057f8", "status": "failed", "error": "failed to queue transaction 2 (Reference: ref_967yg16hhh4q0t0dnsczvud9, Source: bln_a03ef6af-1e5d-46a8-86a9-5fb1f2286f66, Destination: bln_68be0aed-383c-4d27-87db-fb0650093686, Amount: 313333369.18): failed to apply transaction to balances: insufficient funds in source balance. All transactions in this batch have been refunded.", "timestamp": "2025-03-02T19:30:22.43597+01:00" }}
Structured errors are available from Blnk Core 0.15.0 and later.
Bulk endpoints return structured error_detail objects for validation failures. For duplicate references and batch rollbacks, behaviour depends on skip_queue. See API error codes for the full catalogue.
Blnk returns 400 when the request body fails validation before processing starts.
Code
When it happens
TXN_BULK_EMPTY
transactions array is empty
TXN_BULK_LIMIT_EXCEEDED
More than 10,000 items in transactions
TXN_VALIDATION_ERROR
A transaction object is null or invalid
For TXN_VALIDATION_ERROR, error_detail.details.index identifies the zero-based position in transactions[]:
400 Bad Request
{ "error_detail": { "code": "TXN_VALIDATION_ERROR", "message": "transactions[1]: currency: cannot be blank; destination: either destination or destinations is required, not both.", "details": { "index": 1 } }, "errors": "transactions[1]: currency: cannot be blank; destination: either destination or destinations is required, not both."}
Duplicate-reference handling depends on whether items go through the queue.
skip_queue: false
skip_queue: true
On the default queued path, duplicate references are deduplicated in the queue and never recorded. The batch still returns 201 with status: "applied" representing the request was successfully submitted:
transaction_count reflects items in the request, not necessarily rows created. A deduplicated item produces no REJECTED row and no error.
When skip_queue: true, Blnk validates references inline. A duplicate fails the batch and returns 409 with TXN_DUPLICATE_REFERENCE.For atomic batches, previously applied items in the same request are refunded via _refund child transactions.
409 Conflict
{ "batch_id": "bulk_305873c0-518a-470c-bf3a-bc3f3e0b562c", "error": "failed to queue transaction 2 (Reference: sqdup-17372-existing, Source: bln_b4819533-9570-4770-a1a0-25c191da0557, Destination: bln_34111155-4015-4e84-bf7c-13a60794bf0b, Amount: 4.00): transaction validation failed: reference sqdup-17372-existing has already been used. All transactions in this batch have been refunded.", "error_detail": { "code": "TXN_DUPLICATE_REFERENCE", "message": "failed to queue transaction 2 (Reference: sqdup-17372-existing, Source: bln_b4819533-9570-4770-a1a0-25c191da0557, Destination: bln_34111155-4015-4e84-bf7c-13a60794bf0b, Amount: 4.00): transaction validation failed: reference sqdup-17372-existing has already been used. All transactions in this batch have been refunded." }}
When atomic is true, transactions are processed in the order provided in the request.
Each transaction’s reference should be unique. On the default queued path, duplicates are silently deduplicated rather than rejected — see Duplicate references.
When run_async is true, processing happens in the background and you’ll receive an immediate response with a batch ID.
For large transaction batches, using run_async: true is recommended to avoid timeout issues.
Webhook notifications for async processing contain the same detailed error information as synchronous responses, including rollback status.
On the default queued path, status: "applied" means the bulk request was accepted — search by parent_transaction or meta_data.QUEUED_PARENT_TRANSACTION to verify final child statuses.
We are very happy to help you make the most of Blnk, regardless of whether it is your first time or you are switching from another tool.To ask questions or discuss issues, please contact us or join our Discord community.