What you'll build
In this final part you'll take the API from your laptop to a live public URL. Railway handles the server, the build pipeline, and automatic deployments on every Git push.
By the end of this part your API will be:
- Running on a stable public URL (free Railway tier)
- Automatically redeploying whenever you push to
main - Connected to your production Supabase project
- Receiving live Paystack webhook events
Prepare the project for deployment
Add a Procfile in the project root:
web: node dist/index.js
Verify your package.json scripts:
{
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "nodemon --exec ts-node src/index.ts --ext ts"
}
}
Make sure dist/ is in .gitignore so you don't commit compiled files:
echo "dist/" >> .gitignore
Push to GitHub
git init
git add .
git commit -m "Initial API"
Create a repo at github.com/new (name: product-catalog-api), then push:
git remote add origin https://github.com/your-username/product-catalog-api.git
git branch -M main
git push -u origin main
Deploy on Railway
- Go to railway.app and sign in with GitHub
- Click New Project → Deploy from GitHub repo
- Select
product-catalog-api - Railway detects Node.js, runs
npm run build, thennpm start - After the first deploy completes, go to Settings → Domains → Generate Domain
You'll get a URL like https://product-catalog-api-production.up.railway.app.
Set environment variables
In Railway, go to your service and click Variables. Add each variable:
| Variable | Value |
|---|---|
JWT_SECRET |
A long random string (generate with openssl rand -base64 32) |
SUPABASE_URL |
Your Supabase project URL |
SUPABASE_SERVICE_KEY |
Your Supabase service_role key |
PAYSTACK_SECRET_KEY |
Your Paystack secret key |
Railway sets PORT automatically — do not add it manually.
After saving variables, Railway redeploys. Watch the build log to confirm it completes without errors.
Update Paystack webhook URL
In the Paystack dashboard, go to Settings → API Keys & Webhooks and update the Webhook URL to your Railway URL:
https://your-app.up.railway.app/webhooks/paystack
Smoke test the live API
BASE=https://your-app.up.railway.app
# Health check
curl $BASE/health
# Register a user
curl -X POST $BASE/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"securepassword","name":"Live User"}'
# Login
curl -X POST $BASE/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"securepassword"}'
# List products (should return data from Supabase)
curl $BASE/products
Free tier limits: Railway's free hobby plan gives each service 500 execution hours per month — enough for a small production app. If you're building something high-traffic, upgrade to the Pro plan or switch to a VPS. Supabase's free tier gives you 500MB storage and 2GB bandwidth per month, which is plenty to get started.
Automatic deployments
Every time you push to main, Railway will rebuild and redeploy your API automatically. You'll see the deploy status in the Railway dashboard. Zero-downtime deploys are handled by Railway — the old version keeps serving traffic until the new one is ready.
What you've built
Over this five-part series you've built a production REST API with:
- Structured Express + TypeScript architecture
- Zod request validation on every write endpoint
- Supabase PostgreSQL with cascading relations and auto-updated timestamps
- JWT authentication with bcrypt-hashed passwords
- Paystack payment link generation and signed webhook handling
- A live deployment that auto-deploys on push
This API is a solid foundation you can extend for any product — add more resource types, add an admin role check, or connect it to a React or Flutter frontend from the other tutorial series on this site.
BlocWeave