Retries and timeouts
A timeout is not a failure. It is the absence of an answer.
When a POST to create a withdrawal times out, LB Pay may have processed it completely,
partially, or not at all. Your system cannot tell the difference from the client side — and
the two wrong reactions both cost money:
- Treating it as success → the player never receives funds you marked as sent.
- Treating it as failure and refunding the wallet → the player keeps the balance and receives the PIX.
The only safe move is to ask.
Decision procedure
A withdrawal stuck in an unknown state must stay debited until a GET or a webhook confirms
FAILED. Refunding on a timeout is how operators pay twice.
Query endpoints per operation:
| Operation | Query |
|---|---|
| Withdrawal | GET /v1/pix/withdraw/{externalId} |
| Deposit | GET /v1/pix/deposit/immediate-charge/{chargeId} |
| Refund | GET /v1/pix/refund/{endToEndId} |
| Internal transfer | GET /v1/transfer/{externalId} |
Let the response tell you
Error responses carry a retryable boolean. It is false for every business-rule
rejection, because those are deterministic — the same request will be rejected the same way
forever.
Branch on that field instead of hardcoding a list of status codes. It is the API stating its own intent, and it stays correct when new error codes appear.
What is safe to retry
| Situation | Retry? | How |
|---|---|---|
| Timeout / connection reset | ⚠️ Only after a GET | Same externalId |
503 Service Unavailable | ⚠️ Only after a GET | Same externalId |
500 Internal Server Error | ❌ No | The transaction failed. Close it as failed — see below |
401 Unauthorized | ✅ Yes, once | Renew the token first |
400 Bad Request | ❌ No | Fix the payload — retrying sends the same invalid data |
422 Business rule | ❌ No | Definitive. See below |
404 Not Found | ❌ No | Invalid PIX key or account. Notify the player |
A 500 is an answer — a timeout is not
The two look similar in a log and mean opposite things.
| What you got | What it means | What to do |
|---|---|---|
500 in the response | The platform evaluated the request and rejected it. It is a confirmed failure. | Close the transaction as failed. Do not retry the same request, do not poll it. |
No response — timeout, connection reset, 503 | The platform may have processed it. The outcome is genuinely unknown. | Follow the GET procedure above before deciding anything. |
Treating a 500 as unknown leaves a dead transaction polling forever. Treating a timeout as
a 500 closes a transaction that may have settled — and that is how a player gets paid
twice.
Backoff
For the retries that are allowed, use exponential backoff with jitter and a hard cap of 2–3 attempts. Fixed-interval retries from a fleet of workers synchronise into a thundering herd precisely when the platform is already degraded.
attempt 1 → wait ~1s ± jitter
attempt 2 → wait ~4s ± jitter
attempt 3 → wait ~12s ± jitter
→ then stop and alert
Retrying forever is not resilience. After the cap, escalate the operation to a human queue and leave it in a transitional state that your contingency polling job will keep watching.
422 is final — do not retry it
A 422 means the platform evaluated your request and rejected it on a business rule. The
same request will be rejected identically every time.
errorCode | Meaning | Correct action |
|---|---|---|
IGAMING_CPF_MISMATCH | The PIX key belongs to a CPF other than the player's | Ask the player for a key registered to their own CPF |
SECURE_LOOP_ACCOUNT_MISMATCH | Bank details failed Secure Loop verification | Ask the player to confirm the bank details |
Systems that reprocess 422 responses generate support noise and can activate automatic
compliance blocks on the account. Treat 422 as a definitive business outcome and surface
it to the player.
See Ownership rules for why these rejections exist.
Related
- Idempotency — why the
externalIdmust stay the same across retries - Contingency polling — catching operations that never resolved
- HTTP errors — the full error catalogue