Skip to content

Backend

API

Well-engineered APIs — public, internal and integration — built by engineers who run the ones they ship.

Overview

An API is a contract. Before it is code, before it is a URL, it is a promise your system makes to the software that calls it: give me a request in this shape and I will give you a response in that shape, with these errors when things go wrong, and I will not break that promise without warning you. Everything that makes an API good or bad flows from how well that contract is designed and how faithfully it is kept. The endpoints and the JSON are the easy part. The hard part is designing a surface that is coherent, that models the problem rather than the database, and that you can still evolve two years later when a dozen teams and a mobile app you have never met depend on it.

API development is the practice of designing, building and operating those contracts. It spans several styles — REST over HTTP, GraphQL, gRPC, webhooks, and event-driven messaging — each with a genuine reason to exist and a genuine cost. It spans the unglamorous disciplines that separate an API people trust from one they route around: versioning so consumers are not broken by your changes, idempotency so a retried payment does not charge twice, pagination that survives a growing dataset, error handling that tells a caller what actually went wrong, authentication and authorisation that hold up under attack, and rate limiting that keeps one noisy client from taking down the rest. And it spans the developer experience around all of that — an accurate OpenAPI specification, honest documentation, and a surface that a competent engineer can integrate against without emailing you.

We design, build and operate three kinds of API, and the distinction matters because the priorities differ. Public product APIs are consumed by people outside your organisation, so backwards compatibility and documentation are close to sacred — you cannot ring every consumer and ask them to change. Internal service APIs sit between your own services, where you can move faster because you control both ends, but where sloppy contracts still rot into a distributed monolith. And integration APIs connect a client’s systems to each other and to third parties — the CRM to the billing platform, the warehouse to the storefront — where the hard problems are other people’s data models, flaky networks, and failures you must survive rather than prevent. Our angle is the same across all three: good contract design, security taken seriously, and backwards compatibility treated as an engineering discipline rather than an afterthought.

Best for — Organisations building an API that others will depend on — a public product API, a partner integration, a mobile-app backend, or the internal APIs between microservices — and who want a senior team that treats the contract, security and backwards compatibility as the engineering disciplines they are.

Why teams choose API

  • A contract consumers can build on

    A deliberately designed, documented, versioned API lets the teams and partners who depend on it work independently and confidently. They integrate against a stable shape, know exactly what they will get back and how errors are reported, and are not broken by your internal changes — which is the entire point of having an API in the first place.

  • The right style for the job

    REST, GraphQL, gRPC, webhooks and event-driven messaging each solve a different problem. Choosing well — and being willing to mix them — means your public surface is cacheable and conventional, your service-to-service calls are fast and typed, and your asynchronous flows are actually asynchronous instead of a polling loop pretending to be one.

  • Security and compatibility built in, not bolted on

    Authorisation checked on every object, sensible authentication, rate limiting, idempotent writes and a real versioning strategy are designed in from the first endpoint. That is far cheaper than discovering after launch that broken access control leaks data or that you cannot change a field without breaking every consumer at once.

Why businesses choose API

  • You are building an API that other people — partners, another team, a mobile app, the public — will depend on, and you want the contract, versioning and documentation done by engineers who understand what breaking that contract actually costs.
  • You have several systems that need to talk to each other, and you want integration APIs designed to survive real-world failure — retries, idempotency, third-party outages — rather than a happy-path script that falls over the first time a network blips.
  • You want a straight answer on API style — REST, GraphQL, gRPC, events — chosen for your workload and clients rather than for a résumé, including the honest cross-references to when a lighter or heavier tool is the better fit.
  • You care about security beyond a login screen: authorisation enforced per object, sensible OAuth2 or token handling, rate limiting and a gateway, built in from the start rather than after a penetration test finds the hole.

What we build with API

The capabilities this technology is genuinely strong at — and what we most often build with it.

  • Contract-first design and OpenAPI specs

    We design the API surface before writing handlers — resources, operations, request and response shapes, error models and status codes — and capture it as a machine-readable specification, an OpenAPI document for REST or a schema for GraphQL and gRPC. That spec is the source of truth: it generates client SDKs, server stubs, mock servers and documentation, so the description of the API and its actual behaviour cannot drift apart. Designing the contract first also forces the hard modelling questions to the front, where they are cheap to change.

  • Versioning and backwards compatibility

    We treat the contract as a promise, so we plan from day one for how it evolves. That means additive changes wherever possible, explicit versioning where a break is unavoidable, deprecation with a real timeline rather than a surprise, and a discipline about what counts as a breaking change — a renamed field, a tightened validation, a changed default all break somebody. For public and partner APIs especially, this is the difference between an API people trust and one they learn to fear.

  • Authentication and authorisation

    We implement authentication appropriate to the consumer — OAuth2 and OpenID Connect for user-facing and third-party access, API keys for server-to-server, signed tokens where they fit — and we build authorisation as a deliberate layer, checked on every object against the authenticated principal. Broken object-level authorisation is a top vulnerability class precisely because a valid token is treated as a licence to access anything; we never make that assumption, and access control is enforced in the data layer, not guessed from the request.

  • Idempotency, pagination and error handling

    The details that make an API usable under real conditions: idempotency keys so a client can safely retry a write without duplicating it, cursor or keyset pagination that stays correct as data grows rather than offset pagination that skips and repeats rows, and structured, consistent error responses with the right HTTP status codes and enough detail for a caller to know whether to retry, fix their request, or escalate. These are the parts that separate an API engineers can integrate against from one they file support tickets against.

  • Rate limiting, throttling and the gateway pattern

    A single monitored front door — an API gateway — where authentication, rate limiting, throttling, request validation and routing live in one place rather than being reimplemented per service. Rate limits keyed to the client protect you from both accidental hammering and deliberate abuse, throttling smooths bursts, and the gateway gives you one point to enforce policy and observe traffic. We use it where it earns its keep and avoid turning it into a second monolith that every change has to pass through.

  • Documentation, testing and monitoring

    Developer experience is a feature, not a nicety. We generate accurate reference documentation from the spec, write the getting-started narrative a real integrator needs, and provide mock servers and example requests. We test the contract — schema validation, contract tests between consumer and producer, and coverage of the error paths, not just the happy one — and we instrument the API with structured logging, metrics and tracing so that when a consumer says it is slow or broken, we can see why rather than guess.

Use cases

  • A public product API

    An externally-consumed API that developers build on — a REST or GraphQL surface with OAuth2, API keys, rate limiting, generated documentation and a strict backwards-compatibility policy. Here the contract is a product in its own right: it is versioned deliberately, documented honestly, and changed with deprecation windows because you cannot phone every consumer and ask them to update.

  • A partner integration API

    An API that underpins a commercial relationship with a specific partner or set of partners — often a mix of synchronous endpoints for queries and webhooks for pushing events the partner needs to react to. The engineering centres on a stable contract, authentication both parties trust, idempotent operations, and clear semantics for retries and failures, because a broken partner integration is a broken business relationship.

  • A mobile-app backend API

    The backend for an iOS or Android app, where the contract has to stay stable across app-store release cycles you do not control — an old app version is always in the wild. That constraint shapes everything: additive changes only, careful versioning, payloads sized for mobile networks, and often a backend-for-frontend that shapes data for the app rather than exposing raw services and forcing the app into a waterfall of calls.

  • An internal microservices API

    The service-to-service contracts inside a system — frequently gRPC for its speed, typed schemas and streaming, or event-driven messaging where services should be decoupled and asynchronous. The goal is services that can be deployed and scaled independently behind clear contracts, rather than a distributed monolith where every change ripples across service boundaries because the seams were never designed.

When API is the right choice

  • Right when a system needs to be consumed by more than one client or service — a web app and a mobile app, several internal services, a partner integration — because a well-designed API is the seam that lets those consumers move independently against a stable contract instead of reaching into each other’s internals.
  • Right when you are exposing capability deliberately: a public product API you want developers to build on, a partner integration that is part of a commercial relationship, or a mobile-app backend where the contract between app and server is the thing that has to stay stable across app-store release cycles you do not control.
  • Right when systems that were never designed to talk to each other now have to — an integration API that sits between a client’s CRM, billing and fulfilment, translating between their data models and surviving the failures that come with networks and third parties you do not own.
  • Wrong as premature ceremony. If a single application talks only to its own database and will never expose that surface to anyone else, wrapping every data access in an internal HTTP API adds latency, failure modes and versioning obligations for no benefit. A function call is not an API, and pretending it is one is how you get a distributed system with none of the upside.
  • Wrong when the real problem is the underlying data model or service boundaries. An API is a contract over something; if that something is an incoherent tangle of tables or responsibilities, a beautiful API on top only hardens the mess and makes it harder to change. We will say so, and fix the boundary first, before we design a contract that would lock the wrong shape in place.

API: pros and cons

Strengths

  • A clean API decouples producers from consumers: the teams either side of the contract can change their internals, deploy on their own schedule, and scale independently as long as the contract holds.
  • Contract-first design with an OpenAPI or schema definition turns the specification into a shared source of truth — generating client SDKs, server stubs, mock servers and documentation from one artefact, so the docs cannot silently drift from the behaviour.
  • The style is a real choice with real leverage: REST’s HTTP caching and ubiquity, GraphQL’s flexible client-driven queries, gRPC’s speed and streaming for internal traffic, and webhooks and events for push and decoupling — matched to the actual need.
  • A well-run API is observable and defensible: rate limiting, authentication, structured errors and a gateway give you a single, monitored front door where you can enforce policy, watch behaviour, and catch abuse before it becomes an incident.

Trade-offs

  • A badly-designed API is expensive to change once consumers depend on it. The moment a partner or a shipped mobile app is calling your endpoint, you cannot simply rename a field — you are into versioning, deprecation windows and running old and new behaviour side by side. Getting the contract right early is worth far more than it looks, and getting it wrong is a debt you pay for years.
  • Security is critical and easy to get wrong. Broken object-level authorisation — where an authenticated user can read or change data that is not theirs simply by changing an ID — is consistently one of the most common and most damaging API vulnerabilities. Authentication gets most of the attention; authorisation is where the real breaches happen, and it must be enforced on every object, not assumed from a valid token.
  • Chattiness and over-fetching quietly degrade real systems. REST endpoints that return too much, or force a client into a waterfall of calls to assemble one screen, waste bandwidth and time; and resolvers or serialisers that issue one database query per item — the N+1 problem — turn a single request into hundreds. These do not show up on an empty test database and do show up under production load.
  • The style decision carries genuine trade-offs, and REST versus GraphQL in particular has no free answer. GraphQL solves over- and under-fetching but sacrifices easy HTTP caching and adds server complexity and query-cost exposure; REST keeps caching and simplicity but pushes shaping onto the client. gRPC is fast but awkward from browsers. Choosing badly is costly, and choosing by fashion is how it usually happens.

Architecture

We start from the contract and the consumers, not the framework. The first questions are which clients call this API, what they actually need, and what promise the API is making them — because that determines the style, the versioning strategy and the shape of the surface. REST for conventional, cacheable, resource-oriented surfaces; GraphQL when many clients need different shapes of the same data; gRPC for fast, typed internal service-to-service traffic; webhooks and event-driven messaging when the flow is genuinely asynchronous and consumers should be decoupled from producers. Most real systems use more than one, and the skill is in choosing deliberately per boundary rather than picking one style and forcing everything through it.

Behind the contract, we keep the API surface separate from the domain and data layers. The endpoint or resolver validates input, authenticates and authorises, and translates between the public shape and the internal model — it does not reach straight into the database with whatever the client happened to send, because welding the API shape to the table shape makes both impossible to change. Where an API gateway is warranted, it centralises authentication, rate limiting, routing and request validation as one monitored front door. Where events are involved, a broker decouples producers from consumers so a slow or failed consumer does not stall the producer. The architecture serves the contract, and the contract serves the consumers.

Performance

The performance problems that actually hurt APIs are chattiness and the N+1 query. Chattiness is an API that forces a client into a waterfall of calls to assemble one screen, or returns so much data per call that the payload itself is the bottleneck; we fix it by shaping endpoints around how clients consume them, adding the right filtering, field selection and pagination, and using a backend-for-frontend or GraphQL where a single tailored query genuinely beats several round trips. The N+1 problem — one database query per item in a list — is the one that hides on an empty test database and appears the day production data arrives; we design against it with batching, eager loading and query review from the first endpoint, not after the first outage.

Caching is where REST earns its keep and where you have to think hardest with other styles. A URL per resource lets HTTP caches, CDNs and conditional requests do real work with little effort; GraphQL’s single endpoint forfeits most of that and has to rebuild caching by hand, which is a genuine cost in its column of the ledger. Beyond caching, we use pagination that scales, connection pooling, appropriate use of asynchronous processing so a slow downstream call does not hold a request open, and rate limiting so one client cannot starve the rest. We measure against realistic data and load, because API performance judged on a demo database is a number that means nothing.

Security

Authorisation is where APIs are actually breached, and it is where we spend the most care. Broken object-level authorisation — an authenticated user changing an ID in a request to read or modify data that is not theirs — is consistently one of the most common and most damaging API vulnerability classes, precisely because a valid token gets mistaken for permission to access everything. We enforce access control on every object, against the authenticated principal, in the data layer where it cannot be bypassed, and never infer it from the fact that a request authenticated successfully. Function-level and field-level authorisation get the same treatment: what a caller may do is checked, not assumed.

Around that core we build the rest of the posture deliberately: authentication appropriate to the consumer — OAuth2 and OpenID Connect for users and third parties, API keys or signed tokens for machines — with sensible token lifetimes, rotation and scope. Every input is treated as untrusted and validated against the schema at the boundary. Rate limiting and throttling defend against both abuse and accidental floods. We are careful with what error responses reveal, keep secrets out of logs and URLs, enforce transport security, and use the gateway as a single point to apply and monitor these controls. Security here is not a feature we add at the end; it is a property of how every endpoint is built.

Scalability

A well-designed API scales because its contract lets the systems either side of it scale independently. Stateless request handling means the API layer itself scales horizontally behind a load balancer, so the real limits sit in the data stores and downstream services the endpoints touch — which is where caching, batching, read replicas, connection pooling and sensible pagination do the work of keeping those dependencies from being overwhelmed. Rate limiting is a scalability tool as much as a security one: it stops a single client’s traffic from consuming capacity the rest of your consumers need.

For asynchronous and high-throughput flows, event-driven messaging is how you scale past the limits of synchronous request-response. Putting a broker between producers and consumers lets each side absorb bursts, retry independently, and scale to its own load, so a spike in incoming events does not have to be handled at the speed of the slowest downstream step. The trade is added operational complexity and eventual consistency, which we adopt where the throughput or decoupling genuinely warrants it rather than by default. As the surface grows, we keep it governed — consistent conventions, deprecation discipline, and a versioning strategy — so the API scales in coherence, not just in traffic.

API integrations & ecosystem

The technologies we most often pair with it — each links to how we work with it.

How we work

We design the contract before we build the API. That means agreeing the resources or schema, the operations each consumer actually needs, the error model, the authentication and authorisation approach, and the versioning strategy — and capturing it as an OpenAPI or schema specification that becomes the shared source of truth. From that spec we can generate mock servers and client stubs early, so consumers can build against the contract before the implementation is finished, and so the hard modelling decisions surface while they are still cheap to change. An API’s contract is the most expensive thing to get wrong, so it is the first thing we get right.

Then we build in thin vertical slices — a real endpoint, authenticated and authorised, backed by real data, with the error paths and idempotency in place, running in production rather than a demo that quietly N+1s and skips the failure cases. The engineers who design the API are the ones who operate it, which is why the unglamorous parts — rate limiting, structured errors, monitoring, backwards-compatibility discipline — are built in from the outset rather than after the first incident. And because the style decision has real trade-offs, part of our job is the honest call: whether REST or GraphQL fits your consumers, whether an internal boundary needs an API at all, and where a lighter approach would serve you better.

The service behind it

Delivered throughCustom Software Development

What we build with API

The disciplines this technology most often shows up in — from a first build to taking over and stabilising an existing one.

How we deliver

  1. 01

    Discover

    We map the system, the constraints and the business it serves — including the parts nobody documented.

    Architecture brief

  2. 02

    Architect

    Decisions get made, written down and defended before a line of production code exists.

    Decision records

  3. 03

    Build

    Short cycles against working software. You see progress in the product, not in a status deck.

    Shipping increments

  4. 04

    Operate

    Monitoring, incident response and iteration. The system is alive, so the engagement is too.

    Runbooks & SLOs

Industries we use API in

Domain knowledge changes what gets built. A few of the sectors we know before the first meeting.

Also in Backend

Why teams choose us for API

  • Senior engineers only

    APIs are easy to stand up and easy to get wrong — the authorisation holes, the N+1 traps, the versioning mistakes that only bite once a consumer depends on you. The people designing your contract have run APIs in production and have seen how these decisions age. No juniors practising broken access control on your project.

  • We operate what we build

    We run the APIs we ship, so we build the parts that matter under load — idempotency, rate limiting, monitoring, backwards compatibility — in from the start rather than after the first outage or breach. We optimise for the years a public or partner contract has to stay stable, not for the demo that looks clean on an empty database.

  • Honest about style and scope

    REST versus GraphQL, gRPC versus events, and whether an internal boundary needs an API at all are real decisions with real trade-offs, and we make them on your workload rather than on fashion. If a lighter approach serves you better, we will say so — and point you to the REST and GraphQL detail before you commit.

  • Security taken seriously

    Authorisation is where APIs are actually breached, so it is where we spend the most care — enforced on every object, in the data layer, never assumed from a valid token. Authentication, rate limiting and a monitored gateway sit around that core, built in from the first endpoint rather than found missing by a penetration test.

Typical timeline

  1. 01

    Contract and style design

    One to two weeks agreeing the API surface, the style per boundary, the auth and versioning strategy, and the error model — captured as an OpenAPI or schema spec that consumers can build against before the implementation exists.

  2. 02

    First vertical slice

    Two to three weeks delivering real endpoints end to end in production, authenticated and authorised, with idempotency, structured errors and monitoring in place, proving the contract against real data and real failure cases.

  3. 03

    Iterative build

    Endpoint-by-endpoint delivery of the rest of the surface in short cycles, each slice shippable, with rate limiting, pagination, generated docs and client SDKs kept current as the contract grows.

  4. 04

    Hardening and handover

    Security review focused on object-level authorisation, load testing against N+1 and chattiness, versioning and deprecation policy in place, and documentation so your team can own, operate and extend the API.

How pricing works

  • Fixed-scope builds for a well-defined API — a public product API, a partner integration, or a mobile-app backend with a known surface — quoted once the contract and the consumers are understood.
  • Monthly senior engagement for evolving API work, where the surface grows with the product and you want continuity, governance and a stable versioning discipline rather than a one-off deliverable.
  • Focused audits and rescues for existing APIs — authorisation and security review, N+1 and performance problems, a versioning or gateway strategy, or an integration that keeps failing — priced by the assessment.

Hire API engineers

Need API capacity on your own team? We embed named senior engineers into your existing team — reporting to your leads, working in your rituals — so you add capacity without a hiring cycle.

Hire API engineers

Common questions

REST, GraphQL, or gRPC — which should our API use?

It depends on your consumers and your boundaries, and the honest answer is often more than one. REST suits conventional, cacheable, public and resource-oriented surfaces and benefits from free HTTP caching. GraphQL earns its complexity when many different clients need different shapes of the same data, at the cost of harder caching and more server work. gRPC is excellent for fast, typed, internal service-to-service traffic but awkward from browsers. We choose per boundary, on your actual workload, and will point you to the REST and GraphQL detail so you can see the trade-offs rather than take our word for it.

How do you handle versioning without breaking the people who depend on us?

By treating the contract as a promise from day one. We make additive, non-breaking changes wherever possible — new optional fields and endpoints do not break existing consumers — and reserve explicit versioning for changes that genuinely cannot be made compatibly. When a break is unavoidable, we run old and new side by side with a real deprecation timeline rather than a surprise. This matters most for public and partner APIs, where you cannot ring every consumer and ask them to update, and it is exactly why getting the contract right early is worth so much.

What is the most important thing to get right for API security?

Authorisation, and specifically object-level authorisation. The most common and damaging API breaches come from an authenticated user changing an ID to access data that is not theirs, because a valid token gets mistaken for permission to access everything. We enforce access control on every object, against the authenticated principal, in the data layer where it cannot be bypassed — never inferred from the fact that a request authenticated. Authentication, rate limiting and a gateway sit around that, but broken authorisation is where the real damage happens, so it gets the most attention.

Can you build an integration API between our existing systems?

Yes — connecting a client’s systems to each other and to third parties is one of the three kinds of API we build. The hard parts are rarely the endpoints; they are other people’s data models, flaky networks and failures you must survive rather than prevent. So we design integration APIs around idempotency so a retried operation is safe, clear retry and failure semantics, and often a mix of synchronous endpoints and webhooks or events for the asynchronous flows. The aim is an integration that keeps working the first time a third party has an outage, not a happy-path script that falls over when the network blips.

Do we even need an API for this, or is it premature?

Sometimes it is premature, and we will say so. If a single application talks only to its own database and will never expose that surface to anyone else, wrapping internal data access in an HTTP API adds latency, failure modes and versioning obligations for no benefit — a function call is not an API. An API earns its place when a surface has to be consumed by more than one client or service, or exposed deliberately to partners, a mobile app or the public. If the real problem is an incoherent data model or unclear service boundaries, we fix that first, because an API only hardens whatever shape sits beneath it.

Building on API?

A technical conversation with the engineers who would do the work. If we are not the right fit, we will say so on the call.

Two fields required. We reply to real enquiries — no list, no sequence.