_Docs/
Get StartedModulesPlatformDeployCookbookChangelogReference
_Stack
_Modules
  • Ledger
    • Quick Start
    • Core Concepts
      • Accounts
      • Transactions
      • Constraints
      • Source/destination
      • Designing a Chart of Accounts
    • Working with the Ledger
      • Assets & Currency conversion
      • Bi-temporality
      • Bulk processing
      • Filtering queries
      • Idempotency
      • Data isolation with buckets
      • From credit/debit to source/destination
      • Streaming to analytics systems
      • Ledger Schema
    • Advanced Topics
      • Architecting for scale
      • Events Publishers
      • Performance model
  • Numscript
  • Connectivity
  • WalletsEE
  • FlowsEE
  • ReconciliationEE
  1. Modules
  2. Ledger
  3. Working with the Ledger
  4. Bulk processing
Ledger

Bulk processing

The _bulk endpoint allows for efficient processing of multiple requests in a single operation. It supports streaming, parallel or sequential processing, and atomic execution.

Request formats#

Non-streaming#

For standard bulk requests, send operations as a JSON array with Content-Type: application/json:

JSON
[
  {"action": "CREATE_TRANSACTION", "data": {"postings": [{"source": "world", "amount": 100, "asset": "USD", "destination": "alice"}]}},
  {"action": "CREATE_TRANSACTION", "data": {"postings": [{"source": "world", "amount": 200, "asset": "USD", "destination": "bob"}]}}
]

By default, the ledger has a maximum bulk transaction size of 100 items. This limitation helps prevent timeouts when processing large bulk requests.

Streaming#

Bulk requests can be streamed without requiring the entire request to be loaded into memory.

Results are kept in memory until the full stream is complete, which may result in large responses for big datasets. Consider breaking very large operations into smaller batches.

For processing more than 100 items, we recommend using streaming mode instead of increasing the bulk size limit.

To enable streaming, include one of the following content type headers in your HTTP request:

  • For a script stream, include content type application/vnd.formance.ledger.api.v2.bulk+script-stream
  • For a JSON stream, include content type application/vnd.formance.ledger.api.v2.bulk+json-stream

Script stream format

For a script stream, each Numscript transaction must be wrapped with //script and //end delimiters:

Numscript
//script
send [USD 100] (
  source = @world
  destination = @alice
)
//end
//script
send [USD 100] (
  source = @world
  destination = @bob
)
//end

JSON stream format

For a JSON stream, send an array of elements in the request body. Example:

JSON
[
  {"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 for JSON bulk operations (script streams support CREATE_TRANSACTION only):

ActionDescription
CREATE_TRANSACTIONCreates a new transaction in the ledger. Accepts postings or a Numscript (ScriptV1) script, along with optional timestamp, reference, metadata, account metadata, runtime type, and a force flag. Returns the created transaction and its log ID.
ADD_METADATAAdds or updates metadata on a target resource — either an account (by address) or a transaction (by numeric ID). Specify the target using 'targetType' and 'targetId' fields. Returns the log ID of the operation.
REVERT_TRANSACTIONReverts a previously committed transaction by its numeric ID, creating a compensating transaction. Supports a 'force' flag to bypass checks and an 'atEffectiveDate' flag to use the original transaction's effective date. Returns the revert transaction and its log ID.
DELETE_METADATADeletes a specific metadata key from a target resource — either an account (by address) or a transaction (by numeric ID). Specify the target using 'targetType', 'targetId', and the 'key' to remove. Returns the log ID of the operation.

Processing options#

The bulk endpoint accepts the following query parameters:

NameTypeDefaultDescription
continueOnFailurebooleanContinue on failure
atomicbooleanMake bulk atomic
parallelbooleanProcess bulk elements in parallel
schemaVersionstringDefault schema version to use for validation (can be overridden per element)

You cannot set parallel=true and atomic=true at the same time.

The continueOnFailure parameter only applies when parallel=false. In parallel mode, elements are processed independently regardless of this setting.

Example with continue on failure:

curl -X POST $FORMANCE_API_URL/api/ledger/v2/my-ledger/_bulk?parallel=false&continueOnFailure=true
POST/api/ledger/v2/my-ledger/_bulk

This is useful when you want to process as many elements as possible and handle failures separately, rather than stopping the entire batch on the first error.

Idempotency#

Idempotency keys prevent duplicate transactions when replaying bulk requests after failures. Each bulk element can specify its own key.

For script streams, add ik=<key> to the script header:

Numscript
//script ik=transaction-001
send [USD 100] (
  source = @world
  destination = @alice
)
//end

For JSON streams, add the ik field to each element:

JSON
{"action": "CREATE_TRANSACTION", "ik": "transaction-001", "data": {"postings": [{"source": "world", "amount": 100, "asset": "USD", "destination": "bank"}]}}

Detecting duplicate requests

When a request uses an idempotency key that was already processed, the API returns the original response with an Idempotency-Hit: true header. This helps clients distinguish between new and replayed requests.

This header is also returned on individual API endpoints (not just bulk) when using the Idempotency-Key request header.

Configuration#

Bulk size limits#

The 100 item limit applies only to non-streaming requests. If your use case requires a larger limit, you can configure it:

ledger.api.bulk-max-size
example: 100default: noneint

Maximum number of operations allowed in a single bulk API request to the ledger; requests exceeding this limit are rejected.

This setting can be configured on Formance Cloud deployments by contacting your Formance Cloud support team.

Increasing the bulk size does not necessarily improve write performance. Test different values to find the optimal setting for your use case.

Examples#

Script streaming#

To send a bulk request with script streaming:

curl -X POST $FORMANCE_API_URL/api/ledger/v2/my-ledger/_bulk?parallel=true \
  -H "Content-Type: application/vnd.formance.ledger.api.v2.bulk+script-stream" \
  --data-binary @transactions.ns
POST/api/ledger/v2/my-ledger/_bulk

JSON streaming#

To send a bulk request with JSON streaming:

curl -X POST $FORMANCE_API_URL/api/ledger/v2/my-ledger/_bulk?parallel=true \
  -H "Content-Type: application/vnd.formance.ledger.api.v2.bulk+json-stream" \
  --data-binary @transactions.json
POST/api/ledger/v2/my-ledger/_bulk

For more details on the bulk API parameters and response format, see the API Reference.

Bi-temporalityFiltering queries
On This Page
  • Request formats
  • Non-streaming
  • Streaming
  • Processing options
  • Idempotency
  • Configuration
  • Bulk size limits
  • Examples
  • Script streaming
  • JSON streaming