A verification API sits on the critical path of signups, logins and account recovery. When it stumbles, users cannot get in. A resilient integration assumes that networks drop packets, upstream services slow down and occasional responses will be errors, and it plans for each case.
Separate the order from the wait
Two different things happen in an integration. First you create an order and receive a number. Later you wait for a code. Treat these as separate operations with separate timeouts. Creating an order should take seconds. Waiting for a code may take a minute or more, and that wait should never block a web worker.
Timeouts at every layer
Set explicit connect and read timeouts. Library defaults are often infinite or very long, which is how a slow upstream turns into a pile of hung threads.
- Connect timeout: two to three seconds is usually enough.
- Read timeout for order creation: five to ten seconds.
- Overall deadline for the code wait: set by the service profile, not by the HTTP client.
- Always enforce a total deadline so a chain of retries cannot exceed what the user will tolerate.
Retry only what is safe to retry
Retries help with transient failures and hurt when they duplicate side effects. Reads are safe. Creating an order is only safe when you send an idempotency key, which lets the server recognise a repeat. Use exponential backoff with jitter so that thousands of clients do not retry in lockstep.
delay = min(cap, base * 2 ** attempt)
delay = random.uniform(0, delay) # full jitterCircuit breakers
When an upstream fails repeatedly, continuing to call it wastes time and makes recovery slower. A circuit breaker counts recent failures and, past a threshold, fails fast for a short cooldown. After the cooldown it lets a single probe request through. If that succeeds, traffic resumes.
Make failure states explicit
Model the outcome of every request as one of a small set of states, such as created, waiting, received, expired, cancelled and failed. Your UI and your support team should speak the same vocabulary. Ambiguous states like pending-ish are where bugs and refund disputes begin.
Test the unhappy paths
Most integration bugs live in code paths that rarely run. Use a mock server or fault injection to simulate slow responses, 429 and 500 errors, malformed JSON and dropped connections. Run these tests in continuous integration, not just once before launch.
Resilience is mostly discipline: bounded waits, safe retries, early failure and honest state. None of it is exotic, and all of it pays back the first time an upstream has a bad afternoon.
Frequently asked questions
How many retries are reasonable?
Two or three retries with jitter handle most transient faults. More than that usually just delays the failure message. Bound the total time by the user's patience, and stop sooner on errors that retrying cannot fix, such as authentication or validation failures.
Where should the circuit breaker live?
Put it in the client wrapper that every call passes through, so no code path can bypass it. Share state across workers if you can, otherwise each process learns about the outage separately and keeps sending traffic to a failing upstream.
What should the user see when the breaker is open?
A calm, honest message that verification is temporarily unavailable, with an estimate if possible and an alternative path. Avoid spinners that never end. Fast, clear failure is kinder than a long wait that ends in an error anyway.
Put it into practice
Start from the services page and pick the service and country you need. Developers can find endpoints and examples in the API documentation. Learn who we are on the about page, find troubleshooting steps in the help center, or send a question through the contact form. The blog has further reading. When you are set, open the verification dashboard.
Related reading: Handling API Error Codes in Verification Workflows and Idempotency Keys for Verification Order Creation.