Skip to content

Build a store in an afternoon

This guide starts with an AdonisJS 7 application and ends with a persisted order. It uses SQLite and the manual payment driver so every step runs locally.

This guide starts with an AdonisJS 7 application and ends with a persisted order. It uses SQLite and the manual payment driver so every step runs locally. Swap Stripe in after the flow works.

1. Install

Requirements: Node.js 24+, AdonisJS 7, Lucid 22, and a configured database connection.

Adocommerce Kit is prerelease software. The workspace manifests currently use the lockstep 1.3.0-0 version; install matching exact versions of every @adocommercekit/* package in a controlled deployment, and read stability and compatibility before depending on a surface.

pnpm add @adocommercekit/core @adocommercekit/storefront-api

Register the engine and publish the host-owned schema:

node ace configure @adocommercekit/core
node ace configure @adocommercekit/storefront-api
node ace migration:run

@adocommercekit/core adds its provider and commands, writes config/commerce.ts, and publishes migrations into database/migrations. @adocommercekit/storefront-api publishes controllers, validators, middleware, and the /api/commerce route file. Nothing is mounted invisibly from node_modules.

Commit the generated files. They are part of your application.

2. Check the installation

node ace commerce:doctor

A healthy result confirms required tables, payment driver capabilities, driver health checks, and inventory reservation totals. If a deferred or COD provider is registered, doctor also requires retrieveIntent and, in production, jobs.dispatcher: 'queue'. Application boot has already validated configuration and the model registry. Fix doctor errors before seeding.

3. Seed a catalog

node ace commerce:seed:demo

The demo seeder is idempotent. It creates web/retail channels, a Field Supply category tree, outdoor products with variants and descriptions, USD/EUR/IDR prices, multi-location inventory, and flat-rate shipping methods. In the playground, follow with node ace commerce:id:seed:demo (or pnpm --filter playground demo:reset) for Indonesian customers, orders, payments, shipments, and cart funnel data.

Start Adonis and inspect the storefront contract:

node ace serve --hmr
curl http://localhost:3333/api/commerce/products

Each variant includes a serialized price and an availability object. Product controllers preload every relationship used by the transformer; transformers never issue queries.

4. Create a cart

Keep the cookie jar because the default sessionCartToken() strategy stores the anonymous cart token in the session.

curl -c .cart-cookie -b .cart-cookie \
  http://localhost:3333/api/commerce/cart

Copy a variantId from the product response, then add it:

curl -c .cart-cookie -b .cart-cookie \
  -H 'content-type: application/json' \
  -d '{"variantId":"<variant-id>","quantity":2}' \
  http://localhost:3333/api/commerce/cart/lines

If Shield protects your API mutations, expose its XSRF cookie and send X-XSRF-TOKEN, or exempt token-authenticated API routes in config/shield.ts. The generated payment webhook route is excluded because external providers cannot send a CSRF token.

5. Add checkout details

curl -X PUT -c .cart-cookie -b .cart-cookie \
  -H 'content-type: application/json' \
  -d '{"email":"buyer@example.com"}' \
  http://localhost:3333/api/commerce/cart/email

curl -X PUT -c .cart-cookie -b .cart-cookie \
  -H 'content-type: application/json' \
  -d '{"shipping":{"firstName":"Ari","lastName":"Stone","line1":"18 Market Street","city":"Portland","region":"OR","postalCode":"97205","countryCode":"US"}}' \
  http://localhost:3333/api/commerce/cart/addresses

List eligible shipping methods, then select one:

curl -c .cart-cookie -b .cart-cookie \
  http://localhost:3333/api/commerce/cart/shipping-methods

curl -X PUT -c .cart-cookie -b .cart-cookie \
  -H 'content-type: application/json' \
  -d '{"methodId":"<shipping-method-id>"}' \
  http://localhost:3333/api/commerce/cart/shipping-method

6. Place the first order

curl -X POST -c .cart-cookie -b .cart-cookie \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: tutorial-order-001' \
  -d '{"payment":{"method":"manual"}}' \
  http://localhost:3333/api/commerce/checkout

The response is 201 with the storefront order transformer and a seven-day accessToken. Repeating the same request with the same key returns the same order. Reusing the key with a different payload returns E_IDEMPOTENCY_CONFLICT.

Read the order without an account:

curl 'http://localhost:3333/api/commerce/orders/<order-number>?token=<access-token>'

The generated controller also authorizes an authenticated user when the order’s customer record has a matching userId. Signed access tokens remain available for guest orders.

7. Move to Stripe

Install and configure the Stripe package:

pnpm add @adocommercekit/stripe
node ace configure @adocommercekit/stripe

Register stripe() under payments.methods in config/commerce.ts, provide the server key and webhook secret through Adonis environment validation, and point Stripe at:

POST /api/commerce/webhooks/payments/stripe

Do not parse and re-stringify webhook JSON. The published raw-body middleware reads Adonis’s preserved request body and passes those exact UTF-8 bytes to the provider verifier.

The generated checkout controller handles synchronous authorization. It does not publish a complete 3DS/SCA client-confirmation flow. Follow the Stripe guide, including its SCA limitation, before enabling Stripe in production.

Selling in Indonesia instead? @adocommercekit/midtrans and @adocommercekit/xendit implement the same payment port with deferred channels such as QRIS, virtual accounts, and e-wallets, and @adocommercekit/id adds kode-unik manual transfer. Those flows return an order in pending_payment with payment instructions rather than an immediate authorization, and production use requires jobs.dispatcher: 'queue'. Start from packages and imports.

8. Upgrade generated files

node ace commerce:upgrade

The command classifies each publication as add, update, unchanged, or conflict. Conflicts are never overwritten: incoming source and three-way-merge instructions are staged under .commercekit/incoming.

Next steps

Navigation

Type to search…

↑↓ navigate↵ selectEsc close