How We Built a Bakery for Robots

engineeringnextjstutorial

When we set out to build a service that lets AI agents buy cookies for humans, we had one design principle: make it boringly simple. No microservices. No message queues. No Kubernetes. Just a Next.js app that accepts money and ships cookies.

The Stack

Here's the full ingredient list:

  • Next.js 15 (App Router) — server-side API routes, static marketing pages, zero client-side JavaScript for the landing page
  • x402 middleware (@x402/next) — wraps our payment endpoint, handles the 402 flow automatically
  • Goody API — fulfillment partner that actually sends the cookies
  • Prisma + PostgreSQL — tracks order lifecycle from payment to delivery
  • Vercel — deployment, edge functions, the whole deal

The Payment Endpoint

The core of the service is a single API route: POST /api/send-cookie. It's wrapped with withX402() middleware that intercepts unpaid requests and returns a 402 with payment instructions. Once the agent pays and re-submits with a receipt, the middleware lets the request through to our handler.

Inside the handler, we validate the request body with Zod, check the idempotency key against Postgres (no double-ordering!), and kick off the fulfillment pipeline.

The Fulfillment Pipeline

Order states flow through a simple state machine:

  1. payment_verified — the x402 middleware confirmed payment
  2. fulfillment_started — we've called the Goody API
  3. fulfillment_succeeded — Goody accepted the order
  4. fulfillment_failed — something went wrong (payment isn't settled)

Every state transition is recorded in Postgres with timestamps. The GET /api/orders/:id endpoint lets agents check on their order status, with a best-effort live refresh from Goody's API.

What We Didn't Build

No user accounts. No login system. No admin dashboard. No webhook handlers. The x402 protocol eliminates the need for user accounts entirely — the payment is the authentication. And Goody handles fulfillment status through their own systems.

The result is roughly 1,200 lines of TypeScript that handle payments, validation, fulfillment, and order tracking. Sometimes the best architecture is the one with the fewest boxes on the diagram.