Anti-Patterns to Avoid¶
Hardcoding Credentials or Endpoint URLs¶
Problem: Hardcoded API keys end up in version control, logs, CI output, and container images. Hardcoded URLs break when environments change or the gateway URL is updated.
Consequence: Credential leaks, broken deployments, and painful migrations.
Instead: Store API keys in a secrets manager. Load base URLs from environment-specific configuration.
Relying on the Synchronous Response for Final Status¶
Problem: Treating the 200 OK response as confirmation that the payment succeeded and immediately fulfilling the order.
Consequence: The end user receives goods or services before the payment is confirmed. If the payment ultimately fails, you have given away value with no recourse.
Instead: The 200 OK response means pending, not success. Wait for the callback or poll for a terminal status before fulfilling.
Ignoring Webhook Signature Verification¶
Problem: Accepting any POST request to your callback URL without verifying the X-API-KEY header.
Consequence: An attacker who discovers your callback URL can send forged payloads marking fraudulent transactions as success, leading to financial loss.
Instead: Always verify the X-API-KEY header on every callback. Reject requests that fail verification. See Authentication & Security — Validate Callback Authenticity.
Treating All Errors as Retryable¶
Problem: Retrying 400 Validation failed or 422 Business logic error responses in a loop.
Consequence: The request will never succeed because the payload is invalid. You waste time, generate noise in logs, and may trigger rate limits.
Instead: Only retry on transient errors (500, 502, 503, 429, network timeouts). For client errors (400, 401, 404, 422), inspect the error details and fix the root cause. See Error Handling — Distinguish Retryable from Non-Retryable Errors.
Reusing Merchant References After Failure¶
Problem: A transaction fails, so you retry with the same merchantReference but a different amount or payload.
Consequence: The gateway may return a 422 Duplicate error, or worse, if the original transaction was actually accepted, you now have conflicting records.
Instead: Always generate a new merchantReference for a genuinely new transaction. Only reuse the same reference when retrying the exact same request (same amount, same currency, same payer) to leverage idempotency.
Processing Callbacks Synchronously¶
Problem: Performing heavy operations (database writes, external API calls, email sends) inside the callback HTTP handler before returning a response.
Consequence: If processing takes longer than 15 seconds, the gateway times out and marks the delivery as failed. There is no automatic retry — you will need to reconcile that transaction via the status endpoint, and sustained slow responses also feed the per-merchant circuit breaker that can short-circuit subsequent deliveries to your endpoint.
Instead: Accept the callback immediately, return any 2xx status, and process asynchronously. See Webhook Best Practices — Respond Promptly.
Polling Aggressively Instead of Using Webhooks¶
Problem: Polling the Status Check API every few seconds for every pending transaction instead of implementing a callback endpoint.
Consequence: Wasted bandwidth, increased latency to detect status changes, potential rate limiting, and unnecessary load on both your system and the gateway.
Instead: Use webhooks as your primary status update mechanism. Reserve polling for reconciliation sweeps or as a fallback when callbacks are missed.
Ignoring the Reconciliation Reference¶
Problem: Not storing or using the reconciliationReference returned in responses.
Consequence: When disputes arise or you need to match gateway transactions to your internal records, you lack a consistent cross-reference.
Instead: Always send a meaningful reconciliationReference in your requests (e.g., your invoice ID or order ID) and store the value returned in the response for future matching.