Backend & API Development

The Half of the Product Nobody Sees and Everything Depends On

APIs, database design, integrations, queues and monitoring — built so the second year of your product is not spent undoing the first.

  • Documented from the first endpoint
  • Schema agreed before the build
  • Your infrastructure, your accounts
Engineers reviewing an API and database design on a whiteboard
Why It Matters

Front Ends Get Replaced. Backends Get Lived With.

A screen can be redesigned in a fortnight. The data model underneath it, the API contract that a mobile app in the wild is calling, and the integration that finance now depends on are not so easy to move. Most of the expensive rewrites we are called in to do are not caused by bad interface code. They are caused by a backend built for the demo.

So we spend the first days of a project on the parts that are hardest to reverse: what the data really is, who is allowed to touch it, and what the contract looks like to everything that will call it. The rest of the build gets faster once those are settled.

If you already have a backend that is struggling
What We Build

Backend Work, in Practice

APIs for Your Own Apps

One contract that your web app, your mobile app and your future integrations all share, rather than three near-identical backends drifting apart.

Public and Partner APIs

An API your customers or partners build against, with keys, documentation, sandbox credentials and the versioning discipline that keeps them working.

Database Design & Migration

Schema design for new products, and careful migrations for existing ones where the data cannot be lost and the service cannot go down.

Integrations

Payments, accounting, CRM, shipping, e-signature, email and SMS — connected properly, with the failure cases handled rather than ignored.

Queues & Scheduled Work

Background jobs, nightly syncs, report generation and retries, so slow work happens out of the way of the people using the product.

Monitoring & Error Tracking

Uptime checks, structured logs, exception reporting and alerts that reach a person, so a broken endpoint is not discovered by a customer.

Architecture

How a Request Travels Through the System

Every layer has one job. Keeping them separate is what lets you change one without breaking the rest.

Clients

Your web app, mobile apps, a partner integration, a scheduled script. All of them call the same documented API rather than the database directly.

API Edge

TLS, authentication, rate limiting and request validation. A bad or abusive request is rejected here, cheaply, before it reaches anything that costs money to run.

Service Layer

The business rules, permissions and validation. This is where the product actually lives, and the only place a rule is written down once.

Queue & Workers

Slow or failure-prone work — email, exports, third-party calls — goes here so the request can return immediately and nothing is lost if a provider is down.

Database

The record of truth. Indexed for the queries that actually run, migrated deliberately, backed up nightly with a restore that has been tested rather than assumed.

The same shape serves a web application, a mobile app and a SaaS product — which is exactly the point of building the API once.

The Choice People Ask About

REST or GraphQL

Both are fine. The wrong one costs you complexity you did not need or calls you cannot avoid.

REST — the default

Predictable URLs, standard HTTP verbs, one resource per endpoint. What we use unless there is a reason not to.

  • Every developer already knows it, which matters when someone else maintains this
  • Caching works with the tools that already exist, at the edge and in the browser
  • Easy to debug — a URL you can open, a response you can read
  • Rate limiting and monitoring per endpoint are straightforward
  • Weakness: drawing a complex screen can take several round trips
  • Weakness: clients often receive fields they do not need

GraphQL — when it earns it

One endpoint, and the client asks for exactly the fields it wants. Powerful, and heavier to operate.

  • Right when several different clients need different slices of the same data
  • Right when a mobile screen would otherwise make five or six calls
  • The schema is the documentation, and it is strongly typed
  • Cost: caching, rate limiting and query-cost control all need deliberate work
  • Cost: one badly written query can be expensive in a way a REST call cannot
  • Cost: a smaller pool of developers is genuinely comfortable with it

We have shipped both. The honest default is REST, with GraphQL where the number of clients or the shape of the screens justifies it — and a written reason either way, so the next team knows what the decision was for.

Design, Versioning & Docs

An API Is a Promise You Have to Keep

Once something you do not control is calling it, you cannot simply change your mind.

01

Design Before Code

Endpoints, request and response shapes and error formats are agreed on paper first. Consistent naming, consistent pagination, consistent errors — decided once, not per endpoint.

02

Version From Day One

A version in the path from the first release. New fields get added; existing ones do not get renamed or removed without a deprecation window and a message to whoever is using them.

03

Documentation That Runs

An OpenAPI or schema document generated from the code, so it cannot drift, plus example requests and a sandbox key for anyone integrating.

04

Tested Contracts

Automated tests over the endpoints themselves, so a change that would break an existing client fails in the pipeline instead of on a customer phone.

Authentication

Three Mechanisms, Explained Without the Acronym Fog

They are not competitors. They solve different problems, and most products use two of them.

API Keys

A long secret string that identifies a system rather than a person. Right for server-to-server calls between things you control. They must be storable outside the code, rotatable without downtime, and revocable the day someone leaves.

OAuth

How a user grants your product access to their account somewhere else — Google, Microsoft, an accounting system — without ever giving you their password. More moving parts than it looks, and the part people get wrong is refreshing and revoking access.

JWTs

A short-lived signed token the API can verify without looking anything up, which is why they are fast. The trade-off is that a token cannot easily be cancelled before it expires, so they are kept short and paired with a refresh mechanism.

Whatever the mechanism, permissions are checked on every request on the server. An endpoint that trusts the client to have hidden the button is not secured.

Developer working through a database migration plan on screen
Database Schema

The Decision That Is Hardest to Reverse

Everything rests on the schema: every screen, every report, every integration and every row a customer has already typed in. Adding a column is cheap. Splitting one table into three, once there is live data and code depending on the old shape, means a zero-downtime migration, code that works on both shapes at once, and a decision about every row that does not fit.

So we do the boring work first: what the real entities are, which relationships are one-to-many and which are many-to-many, what has to be unique, what must never be deleted, and which queries the product will run a thousand times a day. Then it gets indexed for those queries rather than for the ones we imagined.

  • Every schema change is a versioned migration in the repository
  • Money is stored as exact values, never as floating point
  • Timestamps stored in UTC, converted for display only
  • Records that matter are deactivated, not destroyed
  • Backups restored into a scratch environment before we call them backups
Production Reality

What Happens When Things Go Wrong

Systems fail. The difference between a good backend and a fragile one is entirely in what it does next.

Third-party integrations

  • Every outbound call has a timeout — a slow provider must never freeze your product
  • Retries with backoff for failures that are probably temporary, and none for the ones that are not
  • Requests made so that a repeat cannot charge a card twice or duplicate an order
  • Webhooks verified by signature, and safe to receive twice
  • Credentials in a secrets store, never in the repository
  • A visible degraded state instead of a silent failure that loses the data

Background jobs and queues

  • Email, PDFs, exports, image processing and syncs all run outside the request
  • A failed job lands in a dead-letter queue instead of vanishing
  • Jobs are safe to run twice, because sometimes they will be
  • Scheduled work is monitored — a nightly sync that silently stopped is a classic
  • Queue depth is a metric someone actually watches
  • Heavy reports are generated once and cached rather than rebuilt per view

Rate limiting and abuse

  • Per-key and per-user limits, so one client cannot starve the rest
  • Tighter limits on the expensive endpoints: login, search, export, file upload
  • Clear limit headers and a 429 response, so integrators can behave properly
  • Login attempts throttled and locked after repeated failures
  • Upload size and type limits enforced on the server
  • Limits that can be raised for a specific customer without a deployment

Monitoring and error tracking

  • Exceptions captured with the request, the user and the stack, not just a log line
  • Uptime checks against real endpoints, not only the home page
  • Structured logs with a request id, so one journey can be followed end to end
  • Alerts that reach a person, with thresholds tuned so they are not ignored
  • Response times tracked per endpoint, so slow creep is visible before it is a complaint
  • A written incident note afterwards: what broke, what was done, what prevents a repeat
FAQ

Backend & API Questions

Should we use REST or GraphQL?

REST for most projects. It is simpler to build, simpler to cache, and every developer who comes after us already knows it. GraphQL earns its extra complexity when many different clients need different shapes of the same data, or when a mobile screen is making six calls to draw one view. We choose based on how the data will actually be consumed rather than on which is newer, and we explain the reasoning in plain terms before you agree to it.

What is API versioning and do we need it?

Versioning is what keeps old clients working when you change the API. You need it the moment something you do not control is calling it — a mobile app on a phone you cannot force to update, or a customer integration. We put a version in the path from the first release, add fields rather than renaming them, and never remove anything without a deprecation window and a note to the people using it.

How do you handle API authentication?

Three tools for three jobs. API keys are for server-to-server calls between systems you control: simple, long-lived, and they must be rotatable without downtime. OAuth is for letting a user grant your product access to their account somewhere else, such as Google or an accounting system, without handing over a password. JWTs are short-lived signed tokens that let the API confirm who a user is without a database lookup on every request. Most products end up using two of the three.

Why is the database schema so hard to change later?

Because everything sits on top of it. Screens, reports, integrations, exports and all the data customers have already entered assume the shape it has today. Renaming or splitting a table in a live system means a migration that runs without downtime, code that works both before and after it, and a decision about every row that does not fit the new shape. Adding to a schema is cheap; rethinking one is the most expensive change in software. That is why we spend the extra days on it before the build starts.

What happens when a third-party service we depend on goes down?

We assume it will rather than hope it will not. Calls to outside services get timeouts so a slow provider cannot freeze your application, retries with backoff for failures that are likely temporary, and a queue so the work is never simply lost. Where it matters the product degrades visibly — the order is accepted and the receipt goes out when the provider returns — instead of showing an error and discarding what the user typed.

What are background jobs and queues for?

Anything that takes longer than a person should sit and wait for. Sending email, generating a PDF or a large export, resizing images, syncing with another system, nightly reports. The request hands the work to a queue and returns immediately, and a separate worker process picks it up. Without this, one slow export ties up the web server and every other user notices.

How will we know when something breaks in production?

Error tracking captures every exception together with the request that caused it, uptime checks watch the endpoints that matter, and logs are structured so one request can be followed end to end. Alerts reach a human. If you are on a support retainer they reach us too, and you get a written note of what happened and what was done about it rather than hearing about it from a customer.

Send Us the Hard Part of Your Build

Whether it is a new API, a schema that needs rethinking or an integration that keeps failing — describe it and we will reply with an approach and a budget range within two business days.