Idempotency for Accounting POST requests

Last updated: December 6, 2025

Merge's idempotency feature helps you safely retry POST requests without creating duplicate transactions in connected accounting systems. This guide explains how idempotency works in Merge, how to use it when posting accounting objects, and the best practices to avoid duplicates and data inconsistencies.

What is idempotency?

When you send a POST request with an Idempotency-Key header, Merge treats that request as a unique operation for 24 hours. Within that window:

  • First time with a new key: Merge processes the request and stores a log of the hashed body, status code, and response.

  • Same key with an identical body: Merge does not re-run the write. It returns the original response.

  • Same key with a different body: Merge rejects the request with a 400 error indicating invalid key reuse.

Why this matters:

  • Prevents duplicate invoices, payments, journal entries, or bank transactions during client-side retries or network issues.

  • Allows you to safely retry long-running or rate-limited asynchronous writes.⁠⁠​

Idempotent operations are currently in beta. If you would like to enable this, please contact your Customer Success Manager

Header format and key selection

  • Header: Idempotency-Key: <unique-string>

  • Recommendation: Use a V4 UUID for each individual operation

  • Key lifetime: 24 hours

  • Scope: The key is evaluated against the full request, including URL, body, and relevant headers. Reusing a key for a different request body will result in a 400.

Tip: Generate a fresh UUID per transaction creation attempt on your side.

When to use idempotency

Use Idempotency-Key on any POST that creates accounting records, for example:

  • Invoices

  • Payments

  • Journal entries

  • Expenses or bank transactions

  • Purchase orders and vendor credits

Also use it for:

  • Client-side retry logic after timeouts.

  • Retries following 429 Too Many Requests or transient 5xx responses.

Examples

cURL

curl -X POST "https://api.merge.dev/api/accounting/v1/invoices" \\
  -H "Authorization: Bearer {MERGE_API_KEY}" \\
  -H "Content-Type: application/json" \\
  -H "Idempotency-Key: {uuid}" \\
  -d '{
  "model": {
    "contact_id": "{contact_uuid}",
    "issue_date": "2025-12-01",
    "currency": "USD",
    "line_items": [
      {
        "name": "Service Fee",
        "total_amount": "120.00",
        "quantity": "1",
        "unit_price": "120.00"
      }
    ]
  }
}'

If you need to retry, resubmit with the same Idempotency-Key and identical body within 24 hours of the original request. You’ll receive the same response envelope rather than creating a duplicate.

Best practices

  • Generate keys per object creation: One key per invoice creation, payment creation, etc.

  • Store keys alongside your outbound request record so you can reuse the same key on retries.

  • Keep bodies identical when retrying: Any difference will trigger a 400 for invalid reuse.

  • Pair with robust retry logic:

    • Retry on timeouts and 5xx responses with exponential backoff.

    • Respect 429 rate limits and retry-after guidance.

  • For client-side batching, give each object its own Idempotency-Key

Common scenarios

  • Network timeout after POST: Retry with the same key. Merge returns the same response if the first attempt succeeded or continues tracking the same operation.

  • 400 Bad Request invalid key reuse: Confirm that the request body is identical to the original request that used that key, or generate a new key for a changed request.

  • 429 Too Many Requests: Delay per retry-after guidance, resend with the same key.

  • You need to re-run a changed request: Use a new key. Do not reuse the old key for a different body.

Troubleshooting

  • Received a duplicate record in the downstream system:

    • Ensure every retry reused the same Idempotency-Key.

    • Confirm that all retried bodies were identical.

    • Check that your client did not accidentally regenerate keys on retry.

  • 400 Bad Request invalid reuse errors:

    • Compare the original JSON and the retried JSON. Even small differences like reordered arrays, changed whitespace within strings, or defaults omitted in one request but present in another may result in a different hash.

  • 409 Conflict: "Request with same idempotency key is currently in progress"

    • When two or more requests with the same idempotency key are submitted in quick succession, one is being processed while the other(s) will return a 409 indicating that one is being processed

    • We recommend

      • ensuring two or more of the same requests are not submitted quickly, and

      • catching the 409 exception for when a duplicate request(s) is made while the first one is still processing.

FAQ

  • How long are keys valid?

    • 24 hours. After expiration, reusing the same key will be treated as a brand new request.

  • Do I need idempotency for GET or PATCH?

    • Idempotency-Key is supported for POST operations to prevent duplicate creations

  • Can I use a non-UUID key?

    • Yes. Any sufficiently unique string works, but a UUID v4 is recommended.

  • How many characters can the idempotency key be?

    • 50

If you have complex workloads like bulk writes or need help validating your retry strategy with idempotency, reach out to Merge support!