Build an ecommerce site with AI: payments and safety

Build an ecommerce site with AI: Shopify or custom, Next.js with Stripe, cart, server-side prices, webhooks, stock, emails, legal pages and PCI rules for card data.

Solviera Teknoloji 10 min read Türkçe oku

To build an ecommerce site with AI, you have a coding agent write the product catalogue, cart and checkout step by step; a typical setup is Next.js, a database and a payment provider such as Stripe. The agent writes code fast, but you have to set the rules: prices are calculated on the server, payments are confirmed by webhook, and card data is never stored. Deciding first whether a hosted platform like Shopify already covers your needs is part of the job.

This guide starts with that decision, then walks through building a custom store with an agent in order: data model, cart, checkout, webhooks, stock, emails, legal pages and deployment. Each step has prompts you can copy. At the end there’s a list of the mistakes AI makes most often in ecommerce and a security checklist.

First decision: hosted platform or custom build?

The honest answer is often “hosted platform”. Shopify, WooCommerce and similar platforms handle payments, inventory, shipping integrations, taxes and security updates for you.

Hosted platformCustom build (with a coding agent)
Time to first saleDaysWeeks
Payments, security, updatesThe platform’s jobYour job
Design and flow freedomAs far as themes and apps goUnlimited
Cost structureMonthly fee, sometimes transaction feesHosting + payment provider fees + your time
PortabilityTied to the platformYou own the code

A custom build makes sense when your sales flow isn’t supported (say, subscriptions plus a made-to-order configurator), when you’re adding a store inside an existing app, or when you want to learn and keep full control. That’s the path this guide covers. If you’d rather start with a plain marketing site, read how to build a website with AI first.

1. Stack and setup

For a vibe coding project I suggest a stack agents know well and that’s heavily documented:

  • Next.js (App Router): pages, server code and API routes in one project.
  • PostgreSQL: a managed service (Supabase, Neon and the like) or Docker locally.
  • An ORM (Prisma or Drizzle): schema and migrations live in files, so you and the agent read from the same source.
  • A payment provider: Stripe is the common choice; in some countries local providers are standard (in Turkey, for example, iyzico or PayTR). What they share is that the card is entered in the provider’s form and the result reaches your server by notification.
  • A transactional email service: for order confirmations and shipping notices.
npx create-next-app@latest store
cd store
git status   # create-next-app usually initialises git; if not: git init
claude

2. The first prompt: plan before code

Telling an agent “build me a store” gets you everything in one pass, with the critical parts glossed over. Ask for a plan first:

We're building a small ecommerce site with Next.js (App Router), PostgreSQL and Prisma.
Payments will use Stripe Checkout (card data must never reach our server).

Don't write code yet. First produce a plan covering:
1. Data model: product, product variant (size/colour), order, order item, stock.
2. Pages: product list, product detail, cart, checkout return pages, a simple admin.
3. Payment flow: from cart to creating a checkout session to marking the order paid via webhook.
4. Which operations must happen on the server, and why.

Rules:
- Store prices as integers in the smallest currency unit (cents), never floats.
- Never trust a price, total or discount amount sent from the client.
- Secrets live only in .env; no secret ever reaches client code.
Write the plan and wait for my approval.

Read the plan, fix what you don’t like, then implement it piece by piece: data model, then catalogue, then cart, payments last. Commit after each piece.

3. The product database

A few things I watch for in the data model:

  • Money is an integer. $14.90 is stored as 1490. Stripe and most providers expect amounts in the smallest currency unit anyway.
  • Order items copy the price. The order keeps the product’s name and price at the time of purchase, so a price change tomorrow doesn’t rewrite past orders.
  • Stock lives on the variant. “Blue T-shirt, size M” is its own stock row.
  • Order status is an explicit list: pending, paid, shipped, cancelled, refunded and so on.

When the agent writes a migration, read the file. If it drops a table or a column that already holds data, stop and ask.

4. The cart

The cart, in the browser (or in the database for signed-in users), should hold only product/variant IDs and quantities. Prices and totals are displayed in the cart but always read from the server.

Implement the cart. Store only a list of {variantId, quantity} in localStorage.
The cart page fetches current prices and the total from the server.
Out-of-stock or deleted products show in the cart with a warning.
Limit quantity to 1–10 and enforce that on the server too.

5. Checkout: prices are always computed on the server

Rule number one of ecommerce: never trust a price from the client. Every value in the browser can be changed; anyone can open dev tools and set the total to $1. The right flow:

  1. The client sends the server only the list of variantId and quantity.
  2. The server reads each item’s price and stock from the database and computes the total itself.
  3. The server creates an order with status pending.
  4. The server creates a payment session with the provider (a Stripe Checkout Session, or the local provider’s payment form) and attaches the order ID to it.
  5. The customer is redirected to the provider’s page or iframe and enters their card there.

A trimmed-down idea of the server code:

// app/api/checkout/route.ts (sketch)
const items = await db.variant.findMany({ where: { id: { in: cart.map(c => c.variantId) } } })
const lineItems = cart.map(c => {
  const v = items.find(i => i.id === c.variantId)
  if (!v || v.stock < c.quantity) throw new Error('Out of stock')
  return { price: v.priceCents, quantity: c.quantity }   // price from the DB, not the client
})

Discount codes follow the same rule: the code comes from the client, but whether it’s valid and how much it takes off is decided on the server.

6. Webhooks: paid or not?

A customer landing on your “payment successful” page does not prove the payment went through; that page can be opened by hand, and the customer may have closed the tab. The source of truth is the notification your provider sends to your server (a webhook in Stripe, often called a callback with other providers).

Spell this out to the agent for the webhook endpoint:

Write the Stripe webhook endpoint (/api/webhooks/stripe):
- Verify the signature with STRIPE_WEBHOOK_SECRET; reject unsigned or invalid requests.
- Use the raw request body for signature verification.
- On checkout.session.completed, read the order ID from metadata, and inside one
  database transaction mark the order "paid" and decrement stock.
- Make it idempotent: if the same event arrives twice, the second time changes nothing.
- Compare the amount paid with the order total; if they differ, flag the order and log it.

To test locally, the Stripe CLI can forward events to your machine:

stripe listen --forward-to localhost:3000/api/webhooks/stripe

In Stripe’s test mode, test cards such as 4242 4242 4242 4242 let you run the whole flow without real money. Other providers have sandboxes too; have the agent read their docs on how to verify the notification signature or hash.

7. Stock

Stock is where two people can buy the last item at the same moment. Agents usually write “read, then write”, which leaves a race condition in between. Do the check and the decrement in one atomic query instead:

UPDATE variants SET stock = stock - 2
WHERE id = 'var_123' AND stock >= 2;
-- if zero rows were affected, there wasn't enough stock

Decrementing stock once payment is confirmed (in the webhook) is the simple option; for very limited items you might also hold a short reservation when the checkout session opens. Tell the agent explicitly which one you want.

8. Emails

You need at least two: an order confirmation and a shipping notice. Send the confirmation from the webhook, not from the success page, so it only goes out for orders that were actually paid. The email service’s API key stays on the server. If you skip the SPF/DKIM records your email provider asks for on your sending domain, your emails may end up in spam.

Not code, but part of the store. What’s required depends on where you and your customers are, but most stores need:

  • A privacy policy (covering what you collect and why, plus GDPR or local equivalents where they apply)
  • A cookie notice where required
  • Terms of sale
  • A refund and returns policy, including any statutory withdrawal period
  • Seller details: legal name, address and contact information

If you sell in Turkey, expect a KVKK privacy notice, a distance sales contract and a pre-information form that the customer approves before ordering. You can have the agent add the consent checkboxes at checkout and store the consent with the order. AI can draft these texts, but have a lawyer or accountant review them before going live, and ask them about invoicing and tax obligations.

10. Deployment

Putting the Next.js app on Vercel and the database on a managed PostgreSQL service is the shortest route. Before launch:

  • Enter environment variables (database URL, payment and email keys, webhook secret) in your host’s dashboard.
  • Register the live webhook URL in your payment provider’s dashboard; don’t mix up test and live keys.
  • Run migrations against production deliberately, and take a backup first.
  • Place a small real order in production, refund it, and check the whole flow (email, stock, order status) with your own eyes.

What the AI gets wrong in ecommerce

  • Computing the total in the client and sending it to the server. The most dangerous one. Search the code for a price or total coming from the client and remove it.
  • Marking the order paid on the success page. Without a webhook, order status shouldn’t change.
  • Skipping webhook signature verification, or parsing the body as JSON before verifying, then disabling verification because “it doesn’t work”.
  • Floats for money. The 0.1 + 0.2 problem ends up on invoices.
  • No idempotency. The same webhook arrives twice, stock drops twice, two emails go out.
  • An unprotected admin. It builds an /admin page but forgets authorisation checks on the API routes. Make sure every admin API checks the role on the server.
  • Going live with test keys, or the reverse, using live keys during development.

Security

  • Never store, log or collect card data with your own form. Use the provider’s hosted payment page or form; that keeps your PCI DSS scope as small as possible.
  • Secrets in .env, with .env in .gitignore. Never put a secret key (like sk_...) in client code or in public environment variables (in Next.js, those prefixed NEXT_PUBLIC_).
  • Never paste API keys into the chat. Tell the agent the variable name, not the value.
  • Read what the agent runs. In a terminal connected to a production database, don’t auto-approve migrations, DROPs or bulk UPDATEs.
  • Read every diff, especially payment and auth code. A second pair of eyes is essential here; AI code review covers how to set that up.
  • Collect as little personal data as you can, and keep what you collect behind limited access.

Doing it with AgentVera

Keeping several agents apart helps on a store project, and I do that with AgentVera:

  • Backend and UI in separate worktrees. A Claude Code agent works on payments, webhooks and the data model while a Codex agent builds product pages and the cart UI. Each sits in its own git worktree, all in one workspace.
  • Database manager. Look at the tables, orders and stock the agent created in the database manager without opening another tool; it supports PostgreSQL, MySQL and SQLite.
  • DB Guard. It scans migrations the agent wrote at the end of a turn; DB Guard surfaces risks like a DROP or an UPDATE without WHERE up front.
  • Code review and previews. When a turn ends, code review has a second model look at it; preview environments run each worktree’s dev server at its own address. You still read the payment diff yourself before merging.

None of this gets things right for you; it makes it easier to see what changed.

Quick checklist

  • Hosted vs custom decided on purpose
  • Prices are integers in the smallest unit; order items copy the price
  • The cart holds only IDs and quantities; the total is computed on the server
  • Orders become “paid” only via a signature-verified webhook; the webhook is idempotent
  • Stock is decremented with an atomic query
  • The confirmation email is sent from the webhook; SPF/DKIM set up
  • Privacy, terms, refund policy and seller details are live and reviewed
  • No card data anywhere; secrets only on the server
  • A real order placed and refunded in production

Wrapping up

You can build an ecommerce site with AI, and an agent will write most of it quickly. But what makes a store trustworthy isn’t something the agent does on its own: prices computed on the server, payments confirmed by webhook, stock decremented atomically, no card data kept, and the right legal pages. Put those rules in your first prompt, test every step in test mode, and always read the payment code before you merge it.

Questions

Can I build an ecommerce site from scratch with AI?

Yes. A coding agent can write the product pages, cart, payment integration and admin screens. You still need to understand and test the payment, stock and legal parts, because that’s where bugs that only look like they work cost real money.

Should I use Shopify or build my own store?

If you want to start selling a handful of products quickly, a hosted platform is usually safer and far less work. A custom build makes sense when you need a flow, design or cost structure the platform can’t give you.

Can I store card details in my own database?

You shouldn’t. Card details should be entered in a form or page hosted by your payment provider and never touch your server; that keeps most of the PCI DSS burden with the provider.

How do I know a payment actually went through?

Don’t trust the customer landing on your “success” page; trust the signed webhook your payment provider sends to your server. Mark an order as paid only after verifying that webhook’s signature.

Which legal pages does an online store need?

At minimum a privacy policy, terms of sale, a refund and returns policy and usually a cookie notice, plus clear seller contact details. Requirements vary by country, so have AI draft them if you like, but get them reviewed by someone qualified.

Bring your agents to one desk.

Download AgentVera for free; your installed CLIs are ready to go.

More posts