_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. Idempotency
Ledger

Idempotency

When building financial applications, preventing duplicate transactions is critical. The Formance Ledger provides two mechanisms to ensure transaction uniqueness: idempotency keys and references.

Idempotency Keys#

Add an Idempotency-Key header to your request. If you execute the same request twice with the same key, the system will skip processing and return the original successful response.

How it works#

  1. When you send a request with an idempotency key, the ledger stores a hash of the request along with the response
  2. If you retry with the same key and identical request, the ledger returns the cached response with an Idempotency-Hit: true header
  3. If you retry with the same key but different request parameters, the ledger returns a validation error

Supported endpoints#

Idempotency keys work on all write endpoints:

  • Create transaction (including batch and Numscript)
  • Update metadata (account or transaction)
  • Revert transaction

Scope#

Idempotency keys are scoped to a specific ledger. The same key can be used on different ledgers without conflict.

Example#

curl -X POST $FORMANCE_API_URL/api/ledger/v2/my-ledger/transactions \
  -H "Idempotency-Key: unique-key-123" \
  -H "Content-Type: application/json" \
  -d '{
    "postings": [
      {
        "source": "world",
        "destination": "users:alice",
        "amount": 100,
        "asset": "USD/2"
      }
    ]
  }'
POST/api/ledger/v2/my-ledger/transactions

References#

A reference is a field in the transaction body that acts as a unique identifier. If a transaction with the same reference already exists, the ledger returns an error.

Example#

fctl ledger send my-ledger --numscript '{script}'
POST/api/ledger/v2/my-ledger/transactions

Choosing Between Idempotency Keys and References#

Use CaseRecommendedReason
Retry logic for network failuresIdempotency KeySystem returns success on retry
Mapping to external entities (e.g., orders, refunds)ReferenceGet an error if duplicate, useful for debugging
Unknown or dynamic transaction identityIdempotency KeyWorks with any unique value

Use a reference when you have a unique entity in your system that the transaction should match (e.g., a refund object creating a unique ledger transaction). You'll get an error if you try to re-submit with the same reference.

Use an idempotency key when the identity is less obvious or you want silent duplicate handling. The system will skip processing and return success on retry.

Validation Errors#

Starting with Ledger v2.2, you will receive a VALIDATION error when reusing an idempotency key with different transaction parameters than the original request.

Error format#

JSON
{
  "errorCode": "VALIDATION",
  "errorMessage": "invalid idempotency hash when using idempotency key 'unique-key-123', has computed 'abc123...' but 'xyz789...' is stored"
}

Common causes#

  • Changing any field in the request body (including metadata)
  • Using a different endpoint path
  • Modifying the request after a previous successful call

Best practices#

  1. Use unique keys for each distinct transaction - Generate a new key for each new transaction
  2. Keep request parameters consistent - If retrying, ensure all parameters match the original request exactly
  3. Use a new key if parameters change - If you need to modify the transaction, generate a new idempotency key

Changing any part of the transaction, including metadata, will trigger a validation error when reusing an idempotency key.

If a transaction was created with Ledger v2.1 or earlier, the idempotency hash stored in the database is empty. In this case, the hash validation check is skipped for backward compatibility.

Using Idempotency in Bulk Operations#

When processing bulk transactions, you can specify idempotency keys for individual elements to enable safe retries after partial failures.

Script stream format#

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

JSON stream format#

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

See Bulk Processing for more details on bulk operations.

Filtering queriesData isolation with buckets
On This Page
  • Idempotency Keys
  • How it works
  • Supported endpoints
  • Scope
  • Example
  • References
  • Example
  • Choosing Between Idempotency Keys and References
  • Validation Errors
  • Error format
  • Common causes
  • Best practices
  • Using Idempotency in Bulk Operations
  • Script stream format
  • JSON stream format