Idempotency & Reference Integrity

APIs in crypto and fintech deal with real money, not just data. If the same operation — like sending Bitcoin, off-ramping USDT, or delivering airtime — is processed twice due to retries, bugs, or race conditions, the damage is immediate and irreversible.

This guide explains how to implement Idempotency and reference integrity across your integration, so every action is handled exactly once, no matter how many times it's triggered.

What is Idempotency?

Idempotency means that repeating the same request has no additional effect after the first success

If your app receives the same webhook three times, or the user submits the same “Send USDT” form twice, your system should process it once, not three times.

This applies to:

Webhooks

Payouts

Airtime delivery

BTC or USDT transfers

Stablecoin swaps

Any irreversible value movement

Why It Matters

Without proper idempotency and reference tracking, you risk:

Double sending money

Delivering services multiple times

Recording duplicate ledger entries

Creating inconsistencies between your internal state and Bitnob

Common Causes of Duplicate Processing

1.

Webhook retries

Bitnob retries if your endpoint fails or times out

2.

User double-clicks “Send”

Or refreshes the page mid-request

3.

Your backend times out

You retry the request not knowing the first succeeded

4.

Worker picks up the same job twice

Or your queue misbehaves

All of these can lead to duplicate actions — unless you build idempotency in from the start.

Use reference for Every Transaction

Bitnob allows you to attach a reference to every transaction: swaps, payouts, airtime, etc.

Use this to guarantee one-time execution.

JSON (Reference Example)

It becomes your deduplication key. Bitnob stores and enforces it, and you should too.

How to Build Idempotency Internally

Before processing any transaction, check if the reference already exists.

Node.js (Idempotency Check)

This logic belongs in:

Your webhook handler

Yours user-triggered send/payment endpoint

Your async job processors

Where to Store Reference Integrity

We recommend a dedicated table or collection:

idreferencestatussourcetimestamp
1 offramp_txn_abc123 processedwebhook2025-04-08 12:22:03
2 airtime_txn_20250408 failedjob-worker2025-04-08 12:23:10

This allows:

Fast checks against already-processed references

Auditable logs of what happened

Ability to build dashboards for retries or replay

Transactional Idempotency with Database Locks

If your app supports concurrent processing (e.g., workers, multiple app servers), wrap your logic in a. transactional lock.

Postgres (Row Lock)

Or use Redis with SETNX:

Redis (SETNX)

This avoids race conditions across multiple processes.

Reference Naming Tips

Make references human-readable and unique.

Include a type prefix (e.g., swap*, offramp*, airtime_).

Use a date or sequence suffix to prevent collision (e.g., swap_20250408_001).

Avoid random UUIDs unless you store metadata somewhere else.

This makes logs and dashboards easier to work with.

Idempotency in Bitnob APIs

Every transaction creation endpoint should include a reference:

/api/payouts/initiate

/v1/airtime/purchase

/v1/transactions/convert

/v1/bitcoin/send

/v1/card/fund

The reference is also returned in the webhook. That lets you:

Correlate Bitnob’s event with your internal state

Handle retries without side effects

Build robust reconciliation tooling

Anti-Patterns to Avoid

Not logging the reference:

If you lose the reference or don’t log it, you can’t trace what happened — and support becomes a nightmare.

Using timestamps or random strings:

A reference like 1689731218712 or tx_af12eae is hard to debug. Prefer structured names.

Processing everything as new:

If your system assumes “every request is a fresh one,” it’s vulnerable to network retries, user retries, Bitnob retries — or even bugs in your own retry logic.

Real-World Example

User pays for airtime. You initiate the request to Bitnob with reference : airtime_txn_20250408_001.

Bitnob confirms delivery and sends a webhook. Your server times out before acknowledging the webhook. Bitnob retries the webhook.

Without idempotency:

You process the same delivery again.

You credit the user twice (if applicable).

You potentially send 2x airtime.

With idempotency:

The second webhook sees the reference

The event is ignored (or acknowledged with a 200 OK without further action).

Your app state stays consistent.

Summary

PracticeWhy it matters
Use reference for all txnsDeduplication key
Store and audit referencesTraceability & support visibility
Make references human-readableEasier to debug & reconcile
Lock access in processing codePrevents race conditions
Handle idempotency in webhooksCritical for reliability

Idempotency is a contract between your systems and reality. If you can guarantee exactly-once processing, your system can survive retries, chaos, network issues, and bugs — and still produce the right outcomes.

Ready to keep going? We can move next into Quote Lifecycle & Expiry, where time-sensitive pricing and settlement are the next source of complexity.

Did you find this page useful?