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
Webhook retries
Bitnob retries if your endpoint fails or times out
User double-clicks “Send”
Or refreshes the page mid-request
Your backend times out
You retry the request not knowing the first succeeded
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.
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.
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:
id | reference | status | source | timestamp |
---|---|---|---|---|
1 | offramp_txn_abc123 | processed | webhook | 2025-04-08 12:22:03 |
2 | airtime_txn_20250408 | failed | job-worker | 2025-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.
Or use Redis with 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
Practice | Why it matters |
---|---|
Use reference for all txns | Deduplication key |
Store and audit references | Traceability & support visibility |
Make references human-readable | Easier to debug & reconcile |
Lock access in processing code | Prevents race conditions |
Handle idempotency in webhooks | Critical 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.