Most API integrations don't fail during the demo. They fail three months later, at 2 a.m., when a downstream partner API has a bad day, a webhook gets delivered twice, or a "minor" version bump silently changes a field's data type. By then the integration is load-bearing — invoices are flowing through it, inventory counts depend on it, customer records sync through it — and the failure is no longer a code review comment, it's an incident.
The generic advice ("use REST, validate input, handle errors") isn't wrong, it's just not where production incidents actually come from. In our experience building and maintaining integrations for clients across healthcare, e-commerce, and SaaS platforms, the failures cluster around five specific areas: rate limiting, idempotency, webhook reliability, API versioning, and — the one everyone skips — monitoring that's actually built for integration health rather than generic uptime. This piece goes through each one with the level of detail an engineer actually needs, not a checklist.
Rate Limits Aren't an Edge Case — They're a Certainty
Every third-party API you integrate with has a rate limit, whether it's documented clearly, buried in a support article, or discovered the hard way via a wall of 429 responses. Teams that treat rate limiting as something to "handle later" almost always end up with an integration that works fine in staging and falls over the first time real production volume hits it — batch jobs, bulk syncs, and end-of-month reporting are the usual triggers.
A rate-limit strategy that actually holds up needs three things working together:
- Respect the response headers. Most well-designed APIs return
Retry-AfterorX-RateLimit-Remainingheaders. Ignoring these and rolling your own guess at timing is one of the most common causes of integrations getting rate-limited harder, or temporarily blocked outright. - Exponential backoff with jitter, not fixed retry intervals. A fixed retry delay across many concurrent requests causes retry storms — everything backs off in lockstep and then hits the API again at the same instant. Randomized jitter spreads retries out and is the difference between graceful recovery and a self-inflicted denial-of-service against yourself.
- A circuit breaker for sustained failure. If a downstream API is degraded for an extended period, retrying forever just burns your own compute and queues. Trip a circuit breaker, queue the work, and alert — don't let a partner outage cascade into your own system falling over.
Queue the Work, Don't Block the Request
If an integration is triggered synchronously inside a user-facing request (checkout, form submission, signup), rate-limit handling has to happen off the request thread. Push the call into a background job with its own retry policy. This is one of the reasons integration work and cloud and DevOps engineering are hard to separate cleanly — the queueing infrastructure, retry visibility, and dead-letter handling are as much a platform concern as an integration one.
Idempotency: Making Retries Safe
Here's the failure mode that catches teams off guard: you built solid retry logic for rate limits and network failures, which is correct. But now every retry is a duplicate order, a duplicate charge, or a duplicate record — because the first request actually succeeded on the provider's end, you just never received the response before the connection dropped.
Idempotency isn't a nice-to-have for anything that creates or mutates state — payments, orders, inventory adjustments, ERP postings. It's a requirement. The pattern that works:
- Generate a unique idempotency key per logical operation (not per HTTP attempt) and send it as a header on every retry of that same operation.
- If the provider API supports idempotency keys natively (Stripe and many payment processors do), use theirs. If it doesn't, maintain your own dedup table keyed on the operation and a short TTL, and check it before firing the request.
- For systems where you control both ends — like syncing data into an ERP or CRM platform — design the receiving endpoint to be idempotent by construction: upsert on a natural key rather than blind insert, so a duplicate delivery is a no-op instead of a duplicate row.
This matters more, not less, as integrations multiply. A single integration retrying badly is an annoyance. Five integrations feeding the same ERP without idempotency guarantees is a reconciliation nightmare that shows up as a finance team complaint, not an engineering ticket.
Webhooks: The Silent Failure Mode
Webhooks fail differently than API calls, and that difference is why they cause the most confusing production incidents. With an outbound API call, you know immediately if it failed. With an inbound webhook, silence looks identical to success — until someone notices data is missing days later.
Signature Verification Isn't Optional
Any webhook endpoint that doesn't verify the provider's signature is an open door. Anyone who finds the URL can POST fabricated payloads to it. Every credible webhook provider signs payloads with an HMAC and gives you a secret to verify against — implement that check before anything else touches the payload, and reject unsigned or mismatched requests with no further processing.
Assume At-Least-Once Delivery, Always
Webhook providers guarantee at-least-once delivery, not exactly-once. That means duplicate deliveries are expected, normal behavior, not a bug on their end. If your webhook handler isn't idempotent — using the same dedup approach described above, keyed on the provider's event ID — duplicate deliveries will eventually create duplicate side effects in your system.
Replay Protection and Timing
Signature verification alone doesn't stop replay attacks — a captured, validly-signed payload can be resent later. Check the timestamp included in the signed payload and reject anything outside a reasonable window (five minutes is a common default). And build a real dead-letter queue for webhook processing failures; a webhook that fails processing and is silently dropped is functionally the same as one that was never sent.
Versioning: Surviving a Third-Party API You Don't Control
You don't control the roadmap of the APIs you integrate with. A field gets deprecated, a response shape changes, an enum gains a new value your switch statement doesn't handle — and unless you're deliberate about versioning, that change reaches production as a silent bug rather than a build failure.
A few practices reduce this risk substantially:
- Pin to an explicit API version wherever the provider supports it, rather than always hitting the latest.
- Treat the third-party response schema as untrusted input — validate it against a schema on your side and fail loudly (log and alert) on unexpected shapes, instead of letting a missing field propagate as
nullthrough your business logic. - Subscribe to the provider's changelog or deprecation notices as an operational input, the same way you'd track a security advisory — not something someone happens to notice.
- Isolate the integration behind an adapter layer in your own codebase, so a provider's breaking change is a one-file fix, not a scavenger hunt through every place that API is called.
This is a large part of what disciplined API integration work actually looks like day to day — it's less about the first successful call and more about the structure that keeps the integration correct as the outside world keeps moving.
Monitoring Integration Health, Not Just Uptime
A standard uptime check tells you almost nothing useful about an integration. The endpoint can return 200 while the payload is malformed, a sync job can "complete" while silently skipping records, and a webhook receiver can be perfectly healthy while the provider stopped sending events an hour ago. Integration monitoring needs its own signals:
- Success/failure rate per integration, tracked separately from your application's general error rate — a spike here can be invisible in an aggregate dashboard.
- Latency and timeout trends for outbound calls, since a slowly degrading partner API is a leading indicator, not just a lagging one.
- Webhook delivery gaps — alert if an event type that normally arrives daily hasn't shown up in 48 hours, since that's often a silent subscription or signature failure, not an absence of activity.
- Data reconciliation checks — periodic comparisons between record counts or key totals on each side of the integration, which catch the "everything looks fine but the numbers don't match" class of bug that never triggers a normal error.
These are the checks teams add after their first serious integration incident. Building them in from the start is cheaper than the alternative.
None of This Is Optional at Scale
Individually, each of these failure points seems manageable — "we'll add backoff later," "we'll circle back on idempotency." The problem is they compound. A rate-limit issue triggers retries; retries without idempotency create duplicates; duplicates go undetected because monitoring only watches uptime; and by the time anyone notices, the fix touches production data, not just code. Getting the foundations right before an integration carries real business volume is far cheaper than untangling it afterward.
If you're planning an integration — whether it's a single third-party API or a broader system connecting your CRM, ERP, and customer-facing product — it's worth having the failure modes above reviewed against your specific architecture before you build. Get a quote or get in touch and we can walk through what a resilient integration looks like for your stack.
Need this built, not just explained?
We do this work for clients every week. Send us your situation and we'll come back with a scope and a price range within one business day.
Get articles like this monthly
Engineering and AI notes from real client work. One email a month, unsubscribe anytime.