Skip to main content

How Niobi Ensures Idempotency

In financial API integrations, network drops, client timeouts, and automated retries can cause the same API request to be transmitted multiple times. Idempotency guarantees that initiating the same payment operation multiple times produces the exact same outcome as initiating it once. It prevents double-payouts to recipients, duplicate prompt pushes to payers, and replay attacks.

The Dual-Reference Architecture

Every transaction that reaches Niobi operates on two distinct, complementary identifiers:
  1. Niobi Transaction Reference (depositId / reference):
    • Generated automatically by Niobi when an API request is initialized (depositId for collections, reference for payouts).
    • Returned in the initial API response upon request initiation.
    • Included in all subsequent asynchronous callbacks (payment_step: 2) and status queries.
  2. Merchant Reference (third_party_reference_1 / payment_reference):
    • Generated on your backend before dispatching the API request (e.g. ORDER-2026-001 or TX-DISB-9901).
    • Represents your internal transaction or order identifier.
    • Serves as your idempotency key to prevent duplicates and enable automated reconciliation.
Your SystemMerchant Tracking Layer
third_party_reference_1: “TX-ORD-9001”payment_reference: “PAYOUT-REF-1001”
Niobi SystemNiobi Transaction Layer
depositId: “dep_12345678”reference: “ref_98765432”

Returned upon initial request.


How It Works

Niobi binds your merchant reference to a unique transaction reference upon initial receipt. When a reference uniqueness flag (is_third_party_reference_1_unique: 1 and/or is_third_party_reference_2_unique: 1) is enabled, Niobi enforces duplicate prevention. This active duplicate rejection is currently enforced on disbursements (payouts) only: collection requests accept third_party_reference_1/third_party_reference_2 and their uniqueness flags and Niobi still stores them against the transaction, but a duplicate collection request is not currently rejected based on these flags.

1. Request Initiation & Transaction Reference Assignment

When your server submits a payout or collection request, Niobi assigns a unique transaction reference and maps your third_party_reference_1 to the record.

2. Active Duplicate Prevention (is_third_party_reference_1_unique / is_third_party_reference_2_unique)

To prevent accidental double-payouts during retries or network timeouts, include "is_third_party_reference_1_unique": 1 and/or "is_third_party_reference_2_unique": 1 in params:
Flag Requirement:
Duplicate detection only executes for a reference whose flag is passed as 1 in the request payload. If a flag is omitted or set to 0, Niobi will not check that reference and will process the retry as a new transaction. If both flags are set to 1, Niobi checks third_party_reference_1 first, then third_party_reference_2, and immediately rejects the request on whichever one first matches an existing record, without evaluating further.
When enabled, Niobi verifies uniqueness before debiting or dispatching funds. If a transaction with that reference already exists in the system, Niobi immediately rejects the duplicate submission, naming whichever reference actually matched:

Terminal States & Reference Binding

Once a transaction reaches a terminal status (000000 - Success or 000005 - Failed), both your merchant reference and Niobi’s transaction reference are permanently recorded:
  • Finality: A terminal status indicates the payment has completed.
  • Duplicate Protection: Resubmitting with the same third_party_reference_1 when is_third_party_reference_1_unique: 1 is passed immediately rejects duplicate execution (Duplicate third_party_reference_1 was found!).
  • Verifying Outcome: To check the state of an already-submitted transaction, query the Get Transaction Status API rather than re-initiating the request.
  • Failed Transactions: A 000005 - Failed status represents finality (such as invalid account details, payer decline, or timeout).

Retrying Failed Transactions

If a transfer or collection fails definitively and you need to re-attempt the payment (such as after the customer provides a new phone number or corrects their account details), you must use a new third_party_reference_1. The previous reference cannot be reused to initiate a new transfer.

Benefits of the Suffix Pattern:

  • Traceability: Correlate all attempts related to the same underlying logical order.
  • Webhook Mapping: Match asynchronous callback notifications (payment_step: 2) back to the specific retry attempt.
  • Audit Trail: Maintain an immutable history in your database of each payment attempt and its specific outcome.

Uniqueness Identifiers Reference


Webhook Callback Idempotency on Your Server

Because webhook callbacks traverse public networks, Niobi may re-deliver a terminal callback (payment_step: 2) if your server took longer than 5 seconds to respond with HTTP 200 OK or encountered temporary connectivity issues. Ensure your webhook listener handles duplicate callbacks safely:

Callback Receiver Best Practices:

  1. Verify Inbound Signature: Always verify the incoming SHA-256 signature using your integration Secret Key (senderKey) before parsing data.
  2. Check State Before Crediting: Check whether third_party_reference_1 or Niobi’s reference has already been credited in your database.
  3. Return HTTP 200 on Duplicates: If a callback is received for an already settled order, acknowledge receipt immediately with HTTP 200 OK without duplicating financial credits.
  4. Use Concurrency Locks: Use database row-level locking or unique constraints on third_party_reference_1 to prevent concurrent threads from processing duplicate webhooks simultaneously.

Next Steps

Explore related operational and security guides:
Reconciliation

Transaction Status & Polling

Authoritative guide on querying transaction status and executing dual-layer reconciliation.

Error Codes

Error Handling & Status Codes

Understand status codes, failure diagnostics, and appropriate recovery workflows.