Skip to content

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.