Calling an API in a demo is one line. Calling it ten thousand times a day against a service that rate-limits you, times out, sends events twice, and changes its schema is a workflow, and it is where integrations quietly rot. Here is how to build ones that survive.
Assume every call fails
Networks blip, services 503, timeouts happen. Wrap every outbound call in a bounded timeout and retry with exponential backoff plus jitter, never a tight retry loop (which turns a provider hiccup into a self-inflicted DDoS):
async function call(fn, tries = 4) {
for (let i = 0; i < tries; i++) {
try { return await withTimeout(fn(), 10000); }
catch (e) {
if (i === tries - 1 || !retryable(e)) throw e;
await sleep(2 ** i * 250 + Math.random() * 250); // backoff + jitter
}
}
}
Idempotency keys stop double-actions
If a call times out you do not know whether it succeeded, so you retry, and now you might have charged twice. Send an idempotency key on every mutating request; good APIs dedupe on it server-side so a retry is safe. Derive the key from the operation, not randomly, so the retry carries the same key.
Respect rate limits before they punish you
Read the Retry-After and rate-limit headers and back off proactively; do not wait to get 429ed. For high-volume integrations, put a token-bucket limiter in front of the client so you shape your own traffic instead of getting throttled or banned.
Inbound webhooks: verify, dedupe, ack fast
When you are the receiver: verify the signature (an unsigned webhook endpoint is an open door), dedupe on the event ID (they arrive more than once), and acknowledge within the provider timeout by returning 200 immediately, then processing asynchronously on a queue. Doing the work inline before you ack is how you get storms of retries.
OAuth: refresh before you are locked out
Access tokens expire. Store the refresh token securely, refresh ahead of expiry (not on the 401), and handle the revoked-grant case gracefully: a user can disconnect at any time and your workflow should degrade honestly, not crash.
Version and observe
Pin the API version you built against; providers ship breaking changes and "it worked last month" is not a strategy. Log every call outcome and latency, and alert on error-rate spikes, because an integration you cannot see is one you find out is broken from an angry customer.
The survival kit: timeouts and backoff, idempotency keys, proactive rate-limiting, signed and deduped and fast-acked webhooks, ahead-of-expiry OAuth refresh, pinned versions, and real observability. None of it is glamorous; all of it is why the integration still works at 3am.
