Quick answer: Treat every external API call as something that can fail. Use timeouts, retries with backoff for temporary errors, idempotency keys for writes, queues for work that can wait, and clear status messages for users. Log enough to debug. Never assume a 200 forever. Integrations that only work on the happy path will break in production, usually at the worst moment.
If you need a primer on what an API is, start with What is an API? and API integration. This article focuses on failure behavior.
Failure modes you should expect
- Timeouts: the remote service is slow or your network blips
- HTTP 429: rate limited
- HTTP 5xx: their server error
- HTTP 4xx: your request is wrong (do not blind-retry these)
- Partial success: the remote side accepted the job but your process died before recording it
- Stale data: caches or replicas lag
Shipping, payments, CRM sync and email APIs all hit these. See also shipping API integration and Mailchimp API integration for domain examples.
Timeouts are mandatory
A request without a timeout can hold a PHP worker, a Node process or a queue consumer forever. Set connect and read timeouts deliberately. Fail fast, then retry or park the job.
Retries with backoff
Retry temporary failures (429, 503, network blips). Do not retry permanent client errors (400, 401, 403, 404) without fixing the request.
Use exponential backoff with jitter: wait 1s, 2s, 4s… with a random nudge so many clients do not retry in lockstep. Cap the attempts. After the cap, move the job to a dead-letter queue or an error report a human can see.
Idempotency for writes
If you POST a payment capture or an order create, a retry can double-charge or duplicate unless the API supports idempotency. Patterns:
- Send an idempotency key the provider stores
- Generate your own unique external ID and reject duplicates server-side
- Check “already created?” before creating again
Design your own APIs the same way if partners will call you. REST API design habits pay off here.
Queues beat request-time coupling
When a user clicks “Place order,” do the minimum that must be synchronous (take payment, confirm stock). Push secondary work (ERP push, email, analytics) to a queue. If the ERP is down, the order still exists and the sync retries later.
This is how you avoid turning a third-party outage into an empty cart page.
Circuit breakers and bulkheads
If a dependency is failing hard, stop hammering it for a while (circuit breaker). Isolate thread pools or workers so one slow API cannot exhaust every worker your site has. These patterns are common in larger systems; even small apps can adopt a simple version: “after N failures, pause calls for M minutes and show a degraded message.”
User-facing honesty
Users need status, not silence.
- “Payment received. Fulfilment sync delayed; we will email when it ships.”
- “Address lookup is temporarily unavailable. Enter the address manually.”
Hidden failures create duplicate submissions and support tickets. Clear copy next to forms helps; the same spirit as good form error messages.
Logging and correlation
Log:
- Request ID / correlation ID
- Endpoint and HTTP status
- Latency
- Safe subset of payloads (never raw card data, never secrets)
When a customer complains, you should be able to trace one order across your app and the vendor. API security basics also apply: keys in env vars, least privilege, rotation.
Webhooks need the same care
Inbound webhooks arrive late, twice, or out of order. Verify signatures, respond quickly with 200, and process asynchronously. Store event IDs you have already handled.
WordPress sites using the REST API for headless or mobile apps should apply the same timeout and auth discipline on both sides.
Testing failure
In staging, deliberately:
- Kill the dependency
- Force 429s
- Delay responses past your timeout
- Replay the same webhook twice
If your test plan only covers sunny days, production will be your test plan.
A simple checklist for each integration
- What is the timeout?
- Which errors retry, and with what backoff?
- Is the write idempotent?
- What happens to the user while we wait?
- Where do dead letters go?
- Who gets alerted at 2am?
Rate limits without drama
When you hit 429, respect Retry-After if the provider sends it. Otherwise back off. Spread batch jobs across the day. Cache read-heavy reference data so you are not asking for the same product list every minute.
Document your own rate limits if you publish an API. Partners will guess wrong if you stay silent.
Versioning and breaking changes
Failures are not only outages. Providers deprecate endpoints. Pin API versions when you can. Subscribe to vendor changelogs. Build a staging check that runs critical flows after you upgrade a client library.
Multi-step business processes
Order create, payment capture, shipment create and invoice create are often separate calls. Model them as a state machine in your database: pending_payment, paid, sync_failed, fulfilled. Anyone on support should see the state without reading raw logs.
When a middle step fails, compensate deliberately (refund, release stock, alert). Silent half-orders are how chargebacks start.
Security overlaps with reliability
Expired tokens look like outages. Rotate credentials before they expire. Handle 401 by refreshing the token once, then failing loudly if refresh fails. Do not retry forever with a bad secret. More in API security.
Choosing libraries and HTTP clients
Use a mature HTTP client that supports timeouts and cancellation. Avoid copy-paste curl wrappers with no shared policy. Centralize retry logic so every integration inherits the same rules instead of inventing new ones per endpoint.
In WordPress plugin land, that often means one helper for outbound calls rather than scattered wp_remote_get calls with different assumptions.
Alerting without noise
Page someone for payment capture failures. Do not page someone for a single transient 503 that succeeded on retry. Aggregate errors, alert on rate of failure, and include the correlation ID in the alert body.
Weekly reviews of dead-letter queues catch silent drift that alerts miss.
Contract tests with providers
Where vendors offer sandboxes, run a small suite on a schedule: auth, a read, a write, a deliberate bad call. When the suite fails, you learn about their change before customers do.
Documentation your future self needs
Keep a one-pager per integration: owner, base URL, auth type, timeout values, retry policy, dashboards, and the runbook for “vendor is down.” New engineers should not reverse-engineer this from production.
FAQ
Should every failed call retry automatically?
No. Only transient errors. Fix bad payloads instead of looping them.
Is a longer timeout safer?
Often the opposite. Long timeouts tie up workers. Prefer short timeouts plus retries or queues.
Do serverless functions change this?
They make timeouts and retries even more important because cold starts and short max durations are common. The principles stay the same.
Can Zapier replace careful error handling?
No-code tools help with light syncs. They still fail. You still need monitoring and a plan for stuck tasks. For heavier business systems, custom integration work is often safer.
Build for the outage you know is coming
APIs fail. The difference between a brittle mashup and a dependable product is how you behave when they do. If you need a partner to design or harden those connections, our custom development team works on integrations with recovery paths included, not bolted on later.