Sebastiano Druda

← Back to writing

Guide / Digital Systems & Commerce

An API Integration Is a Relationship Between Failure Modes

The happy path is only the beginning. Design integrations around ownership, retries, idempotency, partial updates and reconciliation of uncertain outcomes.

The request timed out. Did the destination reject it, accept it before the connection failed, or never receive it? A timeout tells the caller that it did not obtain a usable response. It does not necessarily tell the caller what happened to the operation.

That uncertainty is the point where an integration becomes more than field mapping. A second request may repair the situation or duplicate an action. Waiting may be appropriate or leave important data stale. Someone needs a model of the possible states and a way to establish which one occurred.

The integration is not the request. It is what happens when the request fails.

In commerce systems, this matters because a product, listing and channel response can each represent a different moment in a distributed workflow.

Decide who owns each fact

Before choosing polling or webhooks, establish the source of truth. Which system owns the product identifier? Which owns the description? Can a marketplace operator override the price? If a value differs between systems, which direction should reconciliation take?

“Keep everything synchronized” avoids these decisions. A bidirectional flow without ownership rules can repeatedly overwrite legitimate changes or send the same update around a loop. A single source of truth for every field is not always possible, but the exceptions need explicit rules.

For a hypothetical catalogue integration, the internal catalogue might own the approved description while the channel owns its moderation status. Copying the status into the internal view is useful; treating it as a value the catalogue can freely overwrite would misunderstand the relationship.

The integration should therefore carry meaning as well as values. Source, version and operation identity can be as important as the payload itself when deciding whether an update is current and authorized.

Keep the middle understandable

A compact model helps locate the responsibilities:

System A
   ↓ event
Integration layer
   ├─ validate
   ├─ transform
   ├─ retry
   └─ log
   ↓
System B

The diagram leaves out storage, scheduling and recovery details deliberately. Those need to be added according to the actual guarantees required. It is a responsibility sketch, not a production architecture by itself.

Validation checks whether the event is meaningful and usable. Transformation adapts the representation to the destination. Retry handles a defined class of transient failures. Logging preserves enough context to understand the attempt without exposing credentials or unnecessary customer data.

A simple synchronous script may satisfy a low-volume, reversible task. A consequential asynchronous workflow may need durable operation records and a review queue. The shape should follow the failure model rather than the number of APIs involved.

Retry an operation with a contract

RFC 9110 defines idempotency in terms of the intended effect of repeating a request. It does not promise that every response is identical or that an arbitrary business operation becomes safe to repeat because it uses HTTP.

For APIs that support idempotency keys, understand their scope and retention rules. Stripe’s documentation, for example, describes storing results for keyed requests and comparing parameters on reuse. That is a concrete provider contract, not a guarantee offered by all APIs.

A key should represent the same logical operation across retries. Generating a new key after a timeout can defeat the protection. Reusing a key for a genuinely different operation can create a different error. Persist the relationship between the business action and its request identity where necessary.

Retry policies also need a stopping condition. Backoff can reduce repeated pressure on an unavailable service; jitter can spread competing retries. Neither resolves a permanently invalid payload. Separate transient conditions from errors that require a configuration or data change.

A retry budget should cover the whole operation, not only one HTTP call. If a library retries internally and the worker also retries the job, the resulting attempt count may exceed what the operator intended. Record where retry responsibility lives and expose exhausted attempts as a state that can be reviewed.

AWS’s discussion of timeouts, retries and jitter explains how retries can amplify load and why layered retries deserve care. For a small integration, the practical consequence is to choose one understandable policy with bounded attempts, a delay strategy and a route for unresolved work. A larger retry count is not a substitute for establishing whether repeating the action is safe.

Receive events without assuming order

Webhooks reduce the need to repeatedly ask whether something changed, but they introduce another delivery boundary. Verify the provider’s authentication or signature mechanism and follow its acknowledgement requirements. Receiving an event is different from successfully applying its business effect.

Stripe’s webhook guidance explicitly discusses duplicate deliveries and lack of guaranteed event ordering. Other providers may offer different guarantees. The practical lesson is to read the specific contract rather than infer reliable ordering from a successful test callback.

A deduplication record can prevent repeated processing of the same event identifier. It does not automatically solve two distinct events that describe overlapping business changes. Version checks or fetching current authoritative state may be needed to avoid applying stale information.

Delivery history and business state are different kinds of evidence.

Knowing that an event arrived twice does not by itself tell you whether the destination already reflects the intended update.

Represent partial and uncertain outcomes

Suppose a catalogue update succeeds for two channels and fails for a third. A single status on the product cannot describe that result well. Marking the entire product as failed loses confirmed successes; marking it as successful hides the unresolved channel.

Track state at the level where recovery occurs. A record might distinguish prepared, attempted, confirmed, rejected and uncertain operations per destination. The exact names matter less than their connection to observable evidence and an available next action.

A timeout after submission belongs in an uncertain state until the destination can be checked. An explicit validation rejection is a different condition. Combining them into “error” encourages the same retry behavior for situations that require different responses.

This is particularly relevant to multi-marketplace workflows, where destinations have different requirements and acceptance processes. A channel can accept a request while a later processing stage rejects the content. The integration must follow the contract far enough to know which outcome it is reporting.

Reconciliation repairs gaps in the event story

Even a careful event flow can miss a change, encounter an expired credential or stop during a deployment. Reconciliation compares intended state with observed destination state and identifies differences that need action.

That comparison needs the ownership rules established earlier. If an operator is allowed to change a channel-specific field, reconciliation should not automatically “repair” it back to a central value. Otherwise the recovery mechanism becomes another source of damage.

Pull-based reads can complement push-based events. Events provide timely signals; periodic or targeted reads can establish current state. The right frequency depends on freshness requirements, rate limits and the cost of reading the destination.

Be explicit about eventual consistency. It describes a convergence expectation under particular assumptions, not permission for records to disagree forever. Define how long uncertainty can remain before someone needs to investigate and what evidence demonstrates that convergence occurred.

Make operation history useful to a person

An operator should be able to answer which object was affected, what change was attempted, which destination handled it and what is currently known. A correlation identifier can connect logs, operation records and provider responses without embedding secrets in those records.

Authentication expiry and rate limiting should produce actionable states. Refreshing credentials may be an automatic path when the provider supports it; revoked access may require human intervention. A documented retry delay should inform scheduling instead of becoming another generic failure message.

Schema changes deserve explicit detection too. A previously optional field becoming required is a contract change, not a transient outage. Preserve enough response detail to identify that difference while applying appropriate data minimization.

A good integration makes the next safe action visible. That action may be retry, reconcile, correct the source data or stop for review. The happy-path request remains important, but the operating model around it determines whether the connection can be trusted after the first uncertain response.

Sources

  1. AWS: Timeouts, retries, and backoff with jitter — checked 2026-10-11
  2. RFC 9110: HTTP semantics — checked 2026-10-11
  3. Stripe: Webhook delivery behavior — checked 2026-10-11
  4. Stripe: Idempotent requests — checked 2026-10-11

Topics

55 / Essay

Integration Bugs Live Between Systems

Integration failures emerge from timing and conflicting assumptions. Design for retries, duplicate delivery, partial updates and evidence across boundaries.

system integration · 7 min

27 / Field note

One Product, Five Marketplaces, Fifty Different Rules

Multi-channel commerce is an integration problem: shared product facts meet different schemas, publication states and failure modes that need explicit handling.

marketplaces · system integration · 7 min