How to Use Bulk Operations with Streaming in the Ledger API
Last updated: January 16, 2026
This article explains how to use the new streaming feature (starting with ledger 2.2) for bulk operations in the Ledger API, which allows for more efficient processing of large datasets.
Using the Streaming Protocol
To use the streaming feature for bulk operations, follow these steps:
Set the Content-Type header to:
-application/vnd.formance.ledger.api.v2.bulk+script-stream
For large Numscript file streaming. Given the size of files, this removes some significant network delay before the ledger starts working.
-application/vnd.formance.ledger.api.v2.bulk+json-stream
For JSON contentUse the
?parallel=truequery parameter to enable parallel processing (optional)Structure your request body as a stream of NumScript commands
The streaming feature is currently not available in the SDK.
When using
parallel=true, the API processes scripts concurrently (up to 10 workers by default).The API currently keeps all results in memory until the full stream is complete, which may result in large responses for big datasets.
parallel + atomic is not compatible: atomic imply a single sql transaction, and obviously, things need to be sequential in this case
bulk_json
Request format
JSON elements sent one by one in the stream, separated by a new line :
{"action": "CREATE_TRANSACTION", "data": {"postings": [{"source": "world", "amount": 100, "asset": "USD", "destination": "bank"}]}}
{"action": "CREATE_TRANSACTION", "data": {"postings": [{"source": "world", "amount": 200, "asset": "USD", "destination": "bank"}]}}Available actions
* CREATE_TRANSACTION
* ADD_METADATA
* REVERT_TRANSACTION
* DELETE_METADATA
bulk_script
Request format
When using the streaming protocol for script, the API reads the connection line by line. Each script should be separated by //script at the beginning and //end at the end.
If using the parameter parallel=true, each time the api will receive a complete script, it will spawn a task to process the script.
Here's an example:
//script
send [USD 100] (
source = @world
destination = @accounts:1
)
//end
//script
send [USD 100] (
source = @world
destination = @accounts:2
)
//endUsing Idempotency Keys
To prevent duplicate transactions, you can specify an idempotency key for each script. You can use an idempotency key k for each bulk element, in addition to the parallel parameter. In case of failure, you can safely replay the same batch without having duplicates.
Here is an example in Numscript:
//script ik=<your idempotency key>Example cURL Request
Here's an example of how to make a request using cURL:
curl -X POST \
--header "Authorization: Bearer $(fctl cloud generate-personal-token --organization <ID> --stack <ID>)" \
--header 'Content-Type: application/vnd.formance.ledger.api.v2.bulk+script-stream' \
'https://org-stack.eu.sandbox.formance.cloud/api/ledger/v2/test-001/_bulk?parallel=true' \
--data-binary @/Users/johnDoe/formance/streaming/bulk_stream_script.numcurl -X POST \
--header "Authorization: Bearer $(fctl cloud generate-personal-token --organization <ID> --stack <ID>)" \
--header 'Content-Type: application/vnd.formance.ledger.api.v2.bulk+json-stream' \
'https://org-stack.eu.sandbox.formance.cloud/api/ledger/v2/test-001/_bulk?parallel=true' \
--data-binary @/Users/johnDoe/formance/streaming/bulk_json.json