Prompt
How do I set up a payment routing API for failover when an acquirer times out or declines?
Latest observation
To set up a payment routing API with failover, design it so a payment attempt can be retried through alternate acquirers based on clear rules, while avoiding duplicate charges and respecting card/network constraints.
1) Define your routing policy
Create rules for when to fail over, for example:
- Timeouts / no response from acquirer
- Soft declines only, such as:
- insufficient funds
- do not honor
- issuer unavailable
- suspected fraud if your policy allows reroute
- Do not retry on hard declines:
- lost/stolen card
- invalid card
- expired card
- suspected chargeback/fraud blocks
- Stop retrying after a max number of attempts or total latency budget
A good pattern is:
- Timeout → retry on a different acquirer
- Soft decline → retry on another acquirer if allowed
- Hard decline → stop
2) Maintain acquirer metadata
Store per-acquirer config in your routing service:
- acquirer ID/name
- supported countries/currencies
- card brands supported
- payment method support
- priority score / cost
- latency history / uptime
- failover cooldown / circuit breaker status
- credentials / endpoint / API version
This lets you choose the “best next” acquirer dynamically.
3) Use idempotency everywhere
This is critical.
For the client → your API
Require an idempotency key on payment create requests.
For your API → acquirer
Use:
- a merchant reference / order ID
- your own attempt ID
- if the acquirer supports it, an idempotency key or equivalent
This prevents double captures if the original request actually succeeded but your timeout hid the success response.
4) Separate authorization from capture
If your flow allows it:
- Authorize
- If authorization succeeds, capture later
This reduces risk during failover.
For some businesses, you may need auth-and-capture immediately, but then retries must be extra careful.
5) Build a routing engine
Your API can look like:
POST /payments/authorizePOST /payments/capturePOST /payments/refundGET /payments/{payment_id}
Inside authorize:
- Validate request
- Create payment record with status
pending - Select acquirer using routing rules
- Send auth request
- If timeout or retryable decline:
- mark attempt failed
- pick next eligible acquirer
- retry
- If success:
- mark payment authorized
- Return final result
6) Implement a circuit breaker per acquirer
If an acquirer starts timing out or failing a lot, stop sending traffic to it temporarily.
Typical states:
- Closed: normal
- Open: temporarily disabled
- Half-open: test a few requests before restoring
This prevents repeated failures and improves latency.
7) Set retry limits and budgets
Avoid endless failover.
Example:
- max 2–3 acquirer attempts per payment
- max total processing time: 2–5 seconds for synchronous APIs
- only retry on explicitly retryable errors
If the budget is exhausted:
- return
pending_review,failed, ortry_again_later - optionally continue async reconciliation
8) Reconcile ambiguous outcomes
The hardest case is:
- you timeout
- but the acquirer may have actually approved it
To handle this:
- after timeout, query the acquirer transaction status
- if status is unknown, pause before failing over or fail over only if your risk model accepts duplicate exposure
- run post-transaction reconciliation jobs
- use settlement reports / webhooks to detect late approvals
A common safe pattern:
- timeout → check status endpoint
- if unknown after a short wait → either retry with another acquirer or mark as pending until reconciled
9) Standardize error classification
Map acquirer-specific responses into your own categories:
SUCCESSRETRYABLE_TIMEOUTRETRYABLE_SOFT_DECLINENON_RETRYABLE_HARD_DECLINEUNKNOWNSYSTEM_ERROR
This abstraction makes routing logic consistent across acquirers.
10) Track attempts and audit trail
Persist every attempt:
- payment ID
- attempt ID
- acquirer used
- request/response timestamps
- normalized error code
- raw response reference
- outcome
- latency
This helps with:
- debugging
- compliance
- chargeback disputes
- optimization of routing rules
11) Expose clear API responses
Example response on success:
{
"payment_id": "pay_123",
"status": "authorized",
"acquirer": "acq_a",
"attempts": [
{
"acquirer": "acq_a",
"status": "timeout"
},
{
"acquirer": "acq_b",
"status": "authorized"
}
]
}
Example on final failure:
{
"payment_id": "pay_123",
"status": "failed",
"reason": "hard_decline",
"decline_code": "card_stolen"
}
12) Add observability
Monitor:
- success rate per acquirer
- timeout rate
- retry rate
- duplicate/ambiguous auth rate
- approval rate by BIN, country, brand
- p95/p99 latency
- circuit breaker events
Use this data to improve routing decisions.
13) Security and compliance
Make sure you:
- never store raw PAN unless PCI-compliant
- tokenize cards
- encrypt sensitive data
- log carefully to avoid leaking card data
- follow PCI DSS and regional regulations
- handle 3DS / SCA flows correctly where required
14) Recommended failover strategy
A practical starting strategy:
- Route to preferred acquirer based on region/brand/cost
- If timeout:
- query status if available
- if still unresolved, try next acquirer only if duplicate risk is acceptable
- If soft decline:
- retry on alternate acquirer
- If hard decline:
- stop
- Use circuit breakers and health checks to disable unhealthy acquirers automatically
15) Simple pseudo-flow
receive payment request
validate + create idempotent payment
for each eligible acquirer:
if circuit breaker open: skip
send authorization
if success: return success
if hard decline: return failure
if timeout/soft decline: continue
return failed after exhausting routes
If you want, I can also provide:
- a sample API design,
- a database schema, or
- reference code in Node.js / Python / Java for payment failover routing.
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.