API engineering

A practical API integration checklist

An integration is not complete when the happy-path request succeeds. It is complete when both teams understand how the system behaves during duplication, delay, partial failure, schema change, and recovery.

Published 13 August 20269 minute readReviewed by Shago engineering

1. Write the contract before the client

Start with a machine-readable contract and a short human explanation of the workflow. OpenAPI can describe fields and status codes, but it does not explain whether a payment can be retried, when an order becomes final, or which party owns reconciliation. Record those rules next to the schema.

For every field, decide whether it is required, nullable, immutable, sensitive, and safe to log. Specify units and time zones. A timestamp without an offset, an amount without a currency, or an identifier whose casing changes can create failures that pass ordinary validation.

Review question: Could a new engineer implement a compatible client using only the published contract and workflow notes?

2. Give every operation a failure model

Separate failures into categories the client can act on. Validation errors should not be retried unchanged. Authentication failures need credential recovery. Rate limits need a delay. Server errors may be transient, but unlimited retries can turn a small outage into a larger one.

FailureClient behaviorEvidence to retain
Invalid requestStop and correct the payloadField-level error code
Rate limitedHonor Retry-After with jitterLimit policy and request ID
TimeoutCheck operation status before repeatingIdempotency key and trace ID
Server unavailableBounded exponential backoffAttempt count and final outcome

3. Design idempotency deliberately

Networks can lose a response after the server has completed the work. The client sees a timeout and cannot know whether repeating the call will create a duplicate. For write operations, accept an idempotency key, bind it to the authenticated caller and normalized payload, and retain the result for a documented period.

Returning the original result for a repeated key is safer than merely rejecting duplicates. If the same key arrives with a different payload, reject it explicitly. Do not use a timestamp as the key: concurrent work and clock errors make it unreliable.

4. Put limits on retries

Retries need a maximum attempt count, exponential backoff, random jitter, and an overall time budget. Retry only operations that are safe or protected by idempotency. Use circuit breakers carefully: they should reduce pressure on an unhealthy dependency, not hide failures indefinitely.

Async work should expose a status resource or emit a signed webhook. A webhook receiver must also be idempotent because delivery is normally at least once. Record delivery attempts and provide a controlled replay mechanism.

5. Make one request traceable across systems

Generate or accept a correlation ID at the boundary and propagate it through downstream calls, queues, and logs. Metrics should show request rate, error rate, latency percentiles, timeouts, throttling, and queue age. Dashboards without an agreed alert threshold are documentation, not monitoring.

Logs should describe the event and identifiers needed for diagnosis while excluding tokens, credentials, and unnecessary personal data. Decide who may access logs and how long they are retained before production traffic begins.

6. Treat security as part of the protocol

Use TLS, short-lived credentials where possible, least-privilege scopes, and a tested rotation process. Verify webhook signatures against the raw request body and protect against replay with a timestamp tolerance or nonce. Rate-limit authentication failures independently from normal application traffic.

Create an inventory of data crossing the boundary. Minimize sensitive fields, define deletion behavior, and make test fixtures synthetic. A sandbox containing copied production records is still a security risk.

7. Test compatibility and recovery

Contract tests should cover required fields, enum changes, unexpected fields, large payloads, pagination, and error bodies. Add integration tests for timeout-after-commit, duplicate webhook delivery, expired credentials, dependency throttling, and out-of-order events. Run them against a production-like environment.

Before launch, rehearse credential rotation, rollback, queue replay, and reconciliation. If teams cannot explain how they will find and repair one missing or duplicated transaction, the integration is not ready.

8. Release in observable stages

Start with test accounts, then internal traffic, then a small percentage of production volume. Define success and rollback thresholds before each stage. Keep the previous path available until the new integration has survived realistic peak traffic and a complete reconciliation cycle.