claude-codeapitutorialbackenduk-guide

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

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

Key Takeaways

  • Write a detailed API spec before opening Claude Code -- the more precise your brief, the better the output
  • Store all monetary values as integers in pence to avoid floating-point rounding errors
  • Use Supabase row-level security to automatically scope all queries to the authenticated user
  • Deploy to a European hosting region (Railway EU or Vercel) for GDPR compliance
  • Test every endpoint with integration tests before deploying -- Claude Code can generate these for you

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.

FAQs

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.

Key takeaways

  • Write a detailed API spec before opening Claude Code -- the more precise your brief, the better the output
  • Store all monetary values as integers in pence to avoid floating-point rounding errors
  • Use Supabase row-level security to automatically scope all queries to the authenticated user
  • Deploy to a European hosting region (Railway EU or Vercel) for GDPR compliance
  • Test every endpoint with integration tests before deploying -- Claude Code can generate these for you

Looking for data-backed business ideas to build with these tools? Check out our latest free report at ideastack.co

Frequently Asked Questions

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.

Want data-backed business ideas every Thursday?

One validated UK business opportunity per week. Free.