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.
