Failure Designed In
Timeouts, retries and partial failures handled deliberately rather than discovered in production.
Any integration works on the happy path. API development earns its cost in the other cases — the timeout, the duplicate request, the schema that changed without warning. We build REST API and integration work with retries, idempotency and error handling designed in, so a failure downstream does not become a data problem for you.
Integrations are usually estimated on the happy path and spend most of their budget on everything else.
Timeouts, retries and partial failures handled deliberately rather than discovered in production.
A retried request should not create a second order. That is a design decision, not a bug fix.
Clear schemas and versioning, so a change on one side does not silently break the other.
Logging and monitoring built in, so "the integration is broken" can be answered in minutes.
We flag fragile third-party APIs as risk rather than absorbing them quietly into an estimate.
An API is judged on the day something goes wrong, not on the day it ships. These are the checks that make that day survivable.
These are engineering checks. Uptime and throughput figures belong to your infrastructure and your monitoring, and we do not publish figures for other clients' systems.
Two directions of work, and the operational concerns that apply to both.
Discuss a Project →Exposing your data or functionality to other systems.
Connecting to platforms your business already runs on.
Retries, idempotency, rate limits, failure modes.
Authentication, authorization, secrets and audit.
Design, build, secure and document — plus the operational work that keeps it running.
Resources, endpoints, schemas and error formats designed before implementation, because a contract that changes after consumers exist is expensive.
Built to established conventions so any competent developer can consume it without a call, with proper status codes and predictable responses.
Connecting CRMs, payment processors, ERPs, email platforms and shipping providers, with the specifics of each provider's quirks handled rather than assumed away.
Token handling, scopes and permissions implemented with established libraries, and secrets managed properly rather than committed.
Retry logic with backoff, idempotency keys, rate limit handling and queueing, so transient failures do not become data corruption.
Inbound and outbound event handling with signature verification, replay protection and a dead-letter path for what fails.
Request logging, error alerting and enough observability to diagnose a problem without adding instrumentation first.
Written so another developer can integrate without asking you — schemas, auth, error cases and examples.
Where the API is part of a larger product, [web application development](/services/web-development/web-applications/) covers the whole build; where it feeds content to channels, that overlaps [CMS development](/services/web-development/cms/).
The word covers several different jobs, and the failure modes are not the same for any two of them.
Two internal systems that must agree. The hard part is deciding which one is authoritative and what happens when they disagree.
Building against someone else's API, which will change on their schedule rather than yours. Defensive handling is the whole job.
You are the provider. Documentation, versioning and backwards compatibility become product commitments.
Reacting to things that happen elsewhere, where delivery is not guaranteed and duplicates are normal.
Where correctness beats speed and every operation needs to be safe to repeat without doubling a transaction.
Scheduled bulk exchange — product feeds, inventory files, reporting extracts — where volume and completeness matter more than latency.
Contract first, failure modes early, documentation as part of delivery rather than after it.
What moves between which systems, how often, in which direction, and what happens if it does not arrive. This defines everything else.
Schemas, endpoints and error formats agreed before implementation, so both sides can build against something stable.
Retries, idempotency and timeout behavior implemented alongside the happy path, not scheduled for later.
Automated tests covering the failure cases, because those are what break in production and what nobody tests manually.
Logging and alerting configured, documentation written, and handover that lets your team debug without us.
Integration is invisible when it works, which makes it easy to underfund and expensive to skip.
Somebody typing the same information into two systems. It is expensive, it is unreliable, and it is the easiest thing to justify automating.
Two reports that should match and do not, with nobody certain which is right. That is usually an integration problem wearing a reporting costume.
A new marketplace, a new payment provider or a new fulfilment partner, each of which needs your data in its own shape.
Customers or partners asking for programmatic access, at which point your API becomes something you support rather than something you have.
If an off-the-shelf connector genuinely covers it, use it. We will tell you when custom work is not warranted.
Almost every integration problem we are called about is a failure case nobody designed for.
Because production has conditions that development does not — network timeouts, rate limits, provider outages, and data shaped in ways the test cases never contained.
The specific failures repeat. A request times out, gets retried, and creates a duplicate record. A provider changes a field and the parser fails silently. A rate limit is hit during a busy period and requests are dropped rather than queued. A webhook arrives twice and is processed twice.
None of these are exotic, and all of them are cheap to handle at build time and expensive to diagnose afterwards. That is the whole argument for designing failure handling alongside the feature rather than after the first incident.
An idempotent operation produces the same result whether it runs once or five times. For anything that creates records, charges money or sends messages, it is the difference between a safe retry and a serious problem.
The scenario is ordinary: a request to create an order times out. The client does not know whether the server processed it. Retrying risks a duplicate order; not retrying risks a lost one. Without idempotency there is no correct choice.
With an idempotency key, the retry is safe — the server recognizes the request it already handled and returns the same result rather than creating a second order. Any API that creates or charges should support it, and any integration with one should use it.
Use the existing integration if one covers your case. Custom API work is worth it when no off-the-shelf connector fits, when the data mapping is genuinely specific to your business, or when reliability requirements exceed what a generic tool provides.
Middleware platforms sit usefully between the two. For low-volume, non-critical flows they are often the right answer — cheaper than building and adequate for the job.
Where they struggle is volume, complex transformation, and failure visibility. When a middleware flow breaks silently at three in the morning, diagnosing it is frequently harder than debugging code you own. That trade is worth making deliberately rather than by default.
By assuming it will. Providers deprecate versions, change field names and adjust rate limits, usually with notice and occasionally without.
What limits the damage is defensive parsing that fails loudly rather than silently, schema validation on responses, monitoring that alerts when error rates rise, and pinning to a specific API version where the provider supports it.
The failure mode worth avoiding is the silent one. An integration that keeps running while quietly dropping a field can corrupt data for weeks before anyone notices, and reconstructing what was lost is far more expensive than the outage would have been.
Explicit, versioned and boring. Every endpoint documented with its parameters, its response shape and every error it can return — including the ones that are unlikely, because those are the ones nobody handles.
The most useful thing a contract does is make the error cases first-class. Documentation that describes only the successful response leaves every consumer to discover the failure modes in production, one incident at a time.
Consistency matters more than elegance. If one endpoint returns a date as a string and another as a timestamp, every consumer writes special-case code forever. Pick a convention, apply it everywhere, and write it down.
A machine-readable specification is worth the effort. It generates documentation, validates responses in tests, and gives consumers a client without them hand-writing one. It also makes a breaking change visible at review time rather than at runtime.
By deciding in advance what your system does without them, which is a product question as much as a technical one.
Some dependencies are fatal — a payment provider being unavailable means you cannot take payment, and the honest response is a clear message rather than a spinner. Others are not: a recommendation service failing should degrade to a sensible default, not take the page down with it.
Circuit breaking is the pattern that prevents one slow dependency from consuming your capacity. After a number of failures, stop calling for a while, serve the fallback, and try again later. Without it, requests queue up waiting on something that is not coming back.
The subtler failure is a third party that is up but wrong — returning stale data, empty results or a changed field name. Validating what comes back, rather than trusting it, is what turns a silent data corruption into a logged error somebody can act on.
With a strategy chosen before you have consumers, because retrofitting one is considerably harder than starting with it.
The core distinction is between additive and breaking changes. Adding an optional field or a new endpoint breaks nothing and needs no version bump. Removing a field, renaming one, or changing a type breaks every consumer that relied on it, and needs a deliberate path.
Whichever mechanism you choose, the commitment matters more than the mechanism: how long an old version is supported, how consumers are told, and how the deprecation is communicated. An API with no deprecation policy is one that either never improves or breaks people without warning.
For internal APIs with a small number of known consumers, this can be lightweight. For anything public or partner-facing, it is a product commitment with real cost, and it should be priced as one.
Logs that record what was sent, what came back and how long it took — with a correlation identifier that lets you follow one request across every system it touched.
Without correlation, diagnosing a failure means comparing timestamps across several log files and hoping. With it, one identifier retrieves the whole path. It costs almost nothing to add at the start and is genuinely difficult to add later.
Alerting has to distinguish between a request failing and a pattern of failures. One timeout is normal. Twenty in a minute is an incident. An alert on every individual error trains everyone to ignore alerts, which is worse than having none.
And logs need to be readable without exposing what they should not. Request bodies containing personal data or credentials are a common accidental leak. What gets logged is a decision to make deliberately, at build time, rather than something to discover during an audit.
An idempotent operation produces the same result whether it runs once or five times. It matters because networks are unreliable and retries are automatic, which means some of your requests will arrive more than once whether or not you planned for it.
The classic failure is a payment. A request times out, the client retries, and the original request had actually succeeded — so the customer is charged twice. Nothing was defective; the operation simply was not safe to repeat.
The standard solution is an idempotency key: the client generates a unique identifier for the attempt, the server records it, and a repeat with the same key returns the original result rather than performing the action again. It is a small amount of work at build time and prevents a category of problem that is very unpleasant to discover in production.
Reads are naturally safe. Updates that set a value are usually safe. Anything that creates, increments or triggers an external side effect is not, and those are the operations that need this designed in from the start rather than added after an incident.
By assuming they will, and by making the change visible quickly when it happens rather than discovering it through a reconciliation failure weeks later.
The first defense is validating responses instead of trusting them. If a field you depend on is missing or has changed type, that should raise an error immediately at the boundary, not propagate a null through your system until something else breaks in a way that is hard to trace back.
The second is isolation. Third-party calls belong behind a layer of your own, so a change affects one file rather than being scattered across the codebase. It also makes testing possible without hitting their service, which matters more than it sounds.
The third is simply paying attention. Deprecation notices arrive by email to whoever registered the integration, often someone who has since left. Making sure those reach a monitored address is unglamorous and prevents a genuine outage.







Designing and building APIs, and integrating with existing ones — schemas and contracts, authentication, reliability engineering, webhooks, monitoring and documentation. It covers both exposing your own data and connecting to platforms you already use.
An interface following REST conventions — resources addressed by URL, standard HTTP methods and status codes, predictable request and response formats. Its value is that any competent developer can consume it without needing your specific documentation first.
Usually yes. Where a provider's API is fragile or poorly documented, we flag that as project risk rather than absorbing it silently into an estimate — those are the integrations that overrun.
With established libraries and standards rather than custom schemes. Token handling, scopes and permissions implemented properly, and secrets managed through appropriate storage rather than committed to a repository.
That is designed for. Retries with backoff, queueing where the operation can wait, idempotency so retries are safe, and alerting so you know it happened rather than discovering it in a reconciliation.
Yes — schemas, authentication, error cases and examples, written so another developer can integrate without asking. Documentation is part of delivery, not an optional extra.
Where it genuinely fits. GraphQL suits clients needing flexible queries across related data; REST is simpler to cache, monitor and consume for most integration work. We recommend based on the use case rather than preference.
Yes. Repository access, code ownership and documentation transfer as part of handover. You should be able to take the work to another developer without obstruction.
Still deciding if api development is right for you?
Talk to UsIntegration estimates are almost always built from the successful case. Send the request, receive the response, store the result. Written that way, most integrations look like a couple of days of work, and the demo on day three supports that impression.
Then it goes to production, where networks time out, providers rate-limit, payloads arrive malformed, webhooks fire twice, and a field that was always a string is occasionally null. Each of these needs a decision, and each decision is where the actual work was hiding.
This is why integration projects have a reputation for overrunning. Not because they are technically hard, but because they are consistently scoped on the twenty percent that is straightforward.
We would rather have that conversation at the estimate. It makes for a larger number up front and a considerably smaller one across the life of the thing.
Describe the systems and what has to move between them. We will tell you what the integration involves — including the failure cases most estimates leave out.
