claude-code·11 min read·

How to build a REST API with Claude Code (UK guide)

Step-by-step guide to building a production-ready REST API with Claude Code. Covers Express, Supabase, auth, deployment, and UK-specific considerations like VAT and GDPR.

How to build a REST API with Claude Code (UK guide)

You have got a front end. Maybe you built it with Lovable, maybe you scaffolded it in Next.js. But now you need the bit that actually does things -- the API. The backend. The part that talks to your database, handles authentication, processes payments, and serves data to your app.

Building a REST API used to mean weeks of boilerplate, middleware configuration, and debugging CORS errors at 2am. With Claude Code, you can have a production-ready API running in an afternoon.

This guide walks you through building a real API from scratch -- not a toy example, but something you could ship to paying customers. We will use a practical example: a simple SaaS that lets UK freelancers track their invoices and chase late payments.

What you will need

Before you start, make sure you have:

  • Claude Code installed and authenticated (if you have not set this up yet, check our beginner's guide to Claude Code)
  • Node.js 20+ installed
  • A Supabase account (free tier is fine for development)
  • Git for version control
  • About 2-3 hours of focused time

Total cost to get started: nothing. Every tool here has a free tier that will handle development and early users.

Step 1: Define your API spec before you write a line of code

The biggest mistake builders make with AI coding tools is jumping straight into "build me an API." You will get something, but it will be generic and you will spend more time fixing it than you saved.

Instead, write a brief. Here is what a good API brief looks like:

Build a REST API for an invoice tracking SaaS targeting UK freelancers.

Core resources:
- /api/invoices (CRUD) - create, read, update, delete invoices
- /api/clients (CRUD) - manage client records
- /api/payments (read, create) - record payments against invoices
- /api/dashboard (read) - summary stats (total owed, overdue, paid this month)

Requirements:
- Express.js with TypeScript
- Supabase for database (PostgreSQL)
- JWT authentication via Supabase Auth
- All monetary values in pence (GBP) to avoid floating point issues
- Input validation on all endpoints
- Proper error handling with consistent error response format
- CORS configured for localhost:3000 (dev) and production domain

Notice how specific this is. You are telling Claude Code exactly what you want, in a language it understands. The more precise your brief, the better the output.

Step 2: Scaffold the project with Claude Code

Open your terminal, create a new directory, and fire up Claude Code:

mkdir invoice-api && cd invoice-api
claude

Now give Claude Code your brief. Paste the spec from Step 1, and add:

Scaffold this as an Express.js project with TypeScript. Use the following structure:
- src/routes/ for route handlers
- src/middleware/ for auth and validation
- src/lib/ for database client and utilities
- src/types/ for TypeScript interfaces

Include a proper tsconfig.json, .env.example, and package.json with scripts for dev and build.

Claude Code will generate your entire project structure. You should see files appearing for routes, middleware, database configuration, and TypeScript types. Review what it produces before moving on -- this is your foundation.

Step 3: Set up your database schema

Your API needs somewhere to store data. Supabase gives you a PostgreSQL database with a generous free tier -- more than enough for development and your first few hundred users.

Ask Claude Code to generate your database migration:

Create a Supabase migration file for these tables:

clients:
  - id (uuid, primary key)
  - user_id (uuid, references auth.users)
  - name (text, not null)
  - email (text)
  - company (text)
  - created_at (timestamptz, default now())

invoices:
  - id (uuid, primary key)
  - user_id (uuid, references auth.users)
  - client_id (uuid, references clients)
  - invoice_number (text, not null, unique per user)
  - amount_pence (integer, not null) -- GBP in pence
  - vat_pence (integer, default 0)
  - status (enum: draft, sent, paid, overdue)
  - due_date (date, not null)
  - created_at (timestamptz, default now())

payments:
  - id (uuid, primary key)
  - invoice_id (uuid, references invoices)
  - amount_pence (integer, not null)
  - payment_date (date, not null)
  - method (text) -- bank transfer, card, etc.
  - created_at (timestamptz, default now())

Add row-level security policies so users can only access their own data.

Two things to note here. First, we store money as integers in pence, not as decimals. This prevents floating-point rounding errors that plague financial applications. A GBP49.99 invoice is stored as 4999 pence. Second, we use Supabase's row-level security (RLS) so that every query is automatically scoped to the authenticated user. This is not optional -- it is essential.

Step 4: Build your route handlers

Now for the meat of the API. Ask Claude Code to implement each resource:

Implement the /api/invoices routes:

GET /api/invoices - list all invoices for authenticated user, with pagination (limit/offset), filter by status
GET /api/invoices/:id - get single invoice with client details and payment history
POST /api/invoices - create new invoice, auto-generate invoice number (INV-001, INV-002, etc.)
PATCH /api/invoices/:id - update invoice (only if status is draft)
DELETE /api/invoices/:id - soft delete (only if status is draft)

Every route must:
1. Validate input with zod schemas
2. Return consistent JSON responses: { data, error, meta }
3. Handle errors gracefully (400 for validation, 401 for auth, 404 for not found, 500 for server errors)
4. Use the authenticated user's ID from the JWT token

Repeat for clients, payments, and dashboard endpoints. Each time, be specific about the business logic. For example, the dashboard endpoint should calculate:

  • Total outstanding (sum of unpaid invoice amounts)
  • Total overdue (unpaid invoices past their due date)
  • Total received this month
  • Number of invoices by status

Step 5: Add authentication middleware

Your API needs to verify that every request comes from an authenticated user. With Supabase, this means validating JWT tokens:

Create authentication middleware that:
1. Extracts the Bearer token from the Authorization header
2. Verifies it against Supabase's JWT secret
3. Attaches the user object to the request
4. Returns 401 with a clear error message if the token is invalid or missing
5. Skips auth for health check endpoint (GET /api/health)

Claude Code will generate middleware that plugs into your Express routes. The key thing to check: make sure it is using Supabase's getUser() method to verify tokens server-side, not just decoding the JWT locally. Local decoding is faster but does not catch revoked tokens.

Step 6: Add input validation

Never trust data from the client. Every endpoint needs input validation. Zod is the standard choice for TypeScript APIs:

Add zod validation schemas for all request bodies:

createInvoice:
  - client_id: uuid, required
  - amount_pence: positive integer, required
  - vat_pence: non-negative integer, optional (default 0)
  - due_date: future date, required
  - status: enum (draft, sent), optional (default draft)

updateInvoice:
  - amount_pence: positive integer, optional
  - vat_pence: non-negative integer, optional
  - due_date: future date, optional
  - status: enum (draft, sent), optional

Create a validation middleware factory that takes a zod schema and returns Express middleware.

This gives you type-safe validation that runs at the API boundary. If someone sends amount_pence: "not a number", they get a clear 400 error before the request touches your database.

Step 7: Handle UK-specific concerns

Building for the UK market means handling a few things that generic tutorials skip:

VAT calculations

If your users are VAT-registered (threshold is currently GBP90,000 turnover), invoices need VAT handling. Store VAT as a separate field so you can calculate net and gross amounts correctly:

gross = amount_pence + vat_pence
net = amount_pence
vat_rate = vat_pence / amount_pence  // verify this matches expected rate

Date formatting

UK dates are DD/MM/YYYY, not MM/DD/YYYY. Store dates in ISO format (YYYY-MM-DD) in the database but format them correctly in responses destined for the UI:

Add a utility function formatDateUK(isoDate: string): string
that converts '2026-04-13' to '13/04/2026'

Late payment interest

UK law (Late Payment of Commercial Debts Act 1998) allows businesses to charge interest on late invoices at 8% plus the Bank of England base rate. This is a great feature to add to the dashboard:

For overdue invoices, calculate statutory interest:
rate = 8% + Bank of England base rate (currently ~4.5%)
daily_rate = rate / 365
interest = amount_pence * daily_rate * days_overdue

Step 8: Test your API

Before deploying, test every endpoint. Ask Claude Code to generate tests:

Write integration tests using vitest and supertest for all invoice endpoints:
- Create invoice with valid data (expect 201)
- Create invoice with missing fields (expect 400)
- Get invoices for authenticated user (expect 200, only own invoices)
- Update draft invoice (expect 200)
- Update sent invoice (expect 403)
- Delete draft invoice (expect 200)
- Access another user's invoice (expect 404)

Mock Supabase auth to simulate different users.

Run the tests with npm test. Fix anything that fails. Claude Code is excellent at debugging test failures -- paste the error output and ask it to fix the issue.

Step 9: Deploy to production

Your API needs to run somewhere. For a UK-focused SaaS, you want a European hosting region. Two solid options:

Railway (recommended for simplicity):

Install the Railway CLI, then:
railway init
railway up

Set environment variables:
railway variables set SUPABASE_URL=your-url
railway variables set SUPABASE_SERVICE_KEY=your-key
railway variables set JWT_SECRET=your-secret

Railway automatically detects your Node.js project, builds it, and deploys. You get a public URL in about 90 seconds. Their EU region keeps your data in Europe -- important for GDPR compliance.

Vercel (if your front end is already there): If your Next.js front end is on Vercel, you can deploy API routes alongside it. Ask Claude Code:

Convert the Express routes to Next.js API routes (App Router).
Each route handler should use NextRequest and NextResponse.
Keep the same validation and auth middleware pattern.

This keeps your entire stack on one platform and simplifies deployment.

Step 10: Add a health check and monitoring

Production APIs need monitoring. At minimum, add:

GET /api/health - returns { status: 'ok', timestamp, version }

This should:
1. Check database connectivity (run a simple SELECT 1)
2. Return 200 if healthy, 503 if database is unreachable
3. Include the API version from package.json

You can then point an uptime monitor (UptimeRobot has a free tier) at this endpoint to get alerts when your API goes down.

Common mistakes to avoid

Storing money as decimals. Use integers (pence) for all monetary values. GBP19.99 becomes 1999. This prevents rounding errors that will drive your users mad.

Skipping rate limiting. Add basic rate limiting to prevent abuse. Express-rate-limit is a one-line middleware addition. Start with 100 requests per minute per user.

Hardcoding CORS origins. Use environment variables for allowed origins. You will need different values for development (localhost:3000) and production (yourdomain.co.uk).

Not logging errors. Add structured logging from day one. When something breaks in production at 3am, you need to know what happened. Pino is lightweight and fast.

Forgetting about GDPR. Your API stores personal data (names, emails). You need a data deletion endpoint so users can exercise their right to erasure. Add DELETE /api/account that removes all user data.

What you have built

By the end of this guide, you have a production-ready REST API with:

  • Full CRUD operations for invoices, clients, and payments
  • JWT authentication via Supabase
  • Input validation with Zod
  • Row-level security in the database
  • UK-specific features (VAT, date formatting, late payment interest)
  • Integration tests
  • Health monitoring
  • Deployed to a European hosting provider

Total time: 2-3 hours. Total cost: nothing (free tiers). And you built it with Claude Code doing the heavy lifting on boilerplate while you focused on the business logic that matters.

Frequently asked

Can Claude Code build a production-ready API, or is it just for prototypes?

Claude Code is absolutely capable of building production APIs. The key is giving it a detailed spec upfront rather than vague instructions. The authentication, validation, and error handling patterns it generates are the same patterns senior developers use. You still need to review the output and test thoroughly, but the foundations are solid.

How much does it cost to run a REST API for a small SaaS in the UK?

For your first 100-500 users, essentially nothing. Supabase's free tier handles 500MB of database storage and 50,000 monthly active users. Railway's starter plan is pay-as-you-go from about GBP4/month. You are looking at under GBP10/month total until you have meaningful traction.

Should I use Express.js or Next.js API routes for my backend?

If your front end is already on Next.js/Vercel, API routes keep everything in one place and simplify deployment. If you want a standalone backend (easier to scale independently, clearer separation of concerns), Express.js on Railway is the better choice. For most early-stage SaaS products, either works fine.

Do I need to worry about GDPR for my API?

Yes. If you store any personal data (names, emails, IP addresses), you need to comply with UK GDPR. At minimum: add a data deletion endpoint, document what data you collect and why, use a European hosting region, and include a privacy policy. Supabase's EU region and Railway's EU infrastructure make this straightforward.

How do I handle API versioning?

Start simple. Prefix your routes with /api/v1/ from day one. When you need breaking changes later, create /api/v2/ routes alongside the old ones. Claude Code can help you refactor routes into versioned modules when the time comes. Do not over-engineer versioning before you have paying users.

Related reading

More UK-focused guides from the IdeaStack blog.

Build a competitor-teardown agent with Claude Code (UK, 2026)

Build a competitor-teardown agent with Claude Code (UK, 2026)

Validation has a third leg after demand and willingness-to-pay: the competitive picture. This is a small Claude Code agent that scrapes competitor pricing and positioning pages with Firecrawl, extracts structured facts with Claude, diffs them week over week, and alerts you when a rival drops a free tier or hikes a price. Subagent architecture, the ethics, the validation step, and a GBP cost line that undercuts a GBP 100+/mo SaaS.

Read more →

Read keyword data like a builder: free UK tools to size demand (2026)

Read keyword data like a builder: free UK tools to size demand (2026)

Most keyword-tool roundups are written for marketers chasing rankings. This one is for builders deciding whether to write code at all. Search demand is the cheapest, fastest demand signal there is - free, readable in an hour, before you commit a weekend. Here is the free UK stack, how to read volume and intent like a build/no-build decision, the winnable-battle heuristic, and a small Claude Code script that aggregates it all into one CSV.

Read more →

Validate a UK SaaS idea in a weekend with Claude Code (2026)

Validate a UK SaaS idea in a weekend with Claude Code (2026)

Validation is not the opposite of building - it is the cheapest build you will do all month. This is the weekend sequence: mine real complaints, ship a smoke-test landing page in the prospect's own words with Claude Code, drive a little paid traffic, run Mom Test calls, and ask for money. The harness itself is a one-evening Claude Code build. Decision rule, GBP cost line, and the one signal that actually counts.

Read more →

Build a Claude Code morning brief agent (UK indie hacker, 2026)

Build a Claude Code morning brief agent (UK indie hacker, 2026)

A full Claude Code morning brief agent built in a single session. Pulls Companies House new directorships against your watchlist, GSC trailing 7d, and Met Office DataPoint, drafts the brief in Sonnet, sends via Resend at 6:55 every weekday. Deployable code, GBP cost line, smoke check, full pattern end-to-end.

Read more →

Claude Code first-week starter playbook for UK indie hackers: the four commands you actually use, your first feature, and the mistakes that burn a week

Claude Code first-week starter playbook for UK indie hackers: the four commands you actually use, your first feature, and the mistakes that burn a week

Day one to day seven with Claude Code: install, four commands, a hand-written CLAUDE.md, the first feature you should actually build, the four mistakes that burn a week, and the GBP 17/month UK indie hacker budget.

Read more →

The newsletter

One UK business idea, every Thursday

By Tim Bland. Free.