1 1ecommStart building

Headless commerce, without the fragmented stack

One commerce core.
Every experience.

Build a tailored storefront, mobile app, marketplace or connected experience while 1ecomm owns the hard commerce rules behind catalog, cart, checkout preparation and non-hosted order placement.

Developer preview: catalog, anonymous cart, checkout preparation, hosted checkout handoff, capability-gated non-hosted order placement and signed commerce-event webhooks are deployed. Direct payment capture and refunds remain server-controlled operations rather than public browser APIs.

terminal
$ npm create @1ecomm/storefront my-shop

*  Store ID
|  YOUR_STORE_ID
|  OK Store on api.1ecomm.com
|     catalog, cart, checkout-preparation
|  OK Catalog reachable
*  Framework   React · Vue
*  Colour      indigo of 24
|  OK 20 files in my-shop/

$ npm run dev
✓ Themed storefront on the live commerce API
API-firstOpenAPI 3.1 contract
Multi-channelWeb, mobile and server
Server authorityPricing, totals and choices
Tenant-boundKeys cannot select a store

Fastest start

A running, themed storefront from one command

The 1ecomm CLI asks for your store ID, checks it against the live platform before it asks anything else, and writes a storefront connected to your real catalog, stock and prices.

  • No API key to paste

    The publishable key, API URL and capability list are discovered from the store ID. The only value written into your project is the store ID itself.

  • Checked before you commit

    A wrong or unprovisioned store ID fails at the first prompt with what to fix, instead of producing a project that builds and then fails in the browser.

  • Routes follow your store

    Checkout and order lookup are scaffolded only when your store’s capabilities allow them, so you never ship a page that can only fail.

  • Designed with dt-ui

    Choose from 24 palettes in light, dark or follow-the-system. Changing the look later is an attribute on the page, not a rebuild.

Interactive

npm create @1ecomm/storefront@latest my-shop

Scripted, for CI

npx @1ecomm/cli init my-shop \
  --store-id YOUR_STORE_ID \
  --framework react \
  --palette indigo \
  --appearance system \
  -y --install

Frameworks: React and Vue today; Next.js and Angular are planned. Run 1ecomm doctor in any generated project to check it against the live platform. Every starter and SDK is built against the public OpenAPI 3.1 contract.

Open the 1ecomm CLI Field Guide

How headless works

Your experience layer, connected to one governed commerce engine

Headless separates presentation from commerce operations. Your team controls every pixel and interaction; the API remains the authority for data and business rules.

01

Experience channels

React, Next.js, Angular, Flutter, Ionic, WordPress, kiosks and future channels.

02

1ecomm Commerce API

Tenant resolution, product projections, cart lifecycle and eligible checkout choices.

03

Commerce operations

Catalog, inventory, pricing, shipping, fulfillment, payment configuration and governance.

Integration guide

From one store ID to a pending order

Each starter discovers the browser-safe runtime for an already-provisioned store. Follow the server responses; never recreate commerce totals, eligibility or payment capability in the client.

  1. 1

    Set one store ID

    Replace only storeId in the starter’s headless-config.json. The bootstrap endpoint returns public runtime values for a store that an operator has already provisioned. Unknown stores fail closed; they never fall back to sample products.

    // headless.config.json — the only value you replace
    { "storeId": "YOUR_STORE_ID" }
    
    const runtime = await fetch(
      `https://api.1ecomm.com/v1/headless/stores/${storeId}/config`
    ).then(r => r.json());
    
    const response = await fetch(
      `${runtime.data.apiUrl}/v1/headless/products?limit=12`,
      { headers: { 'x-publishable-key': runtime.data.publishableKey } }
    );
    
    if (!response.ok) throw new Error('Catalog unavailable');
    const catalog = await response.json();
  2. 2

    Create an isolated shopper cart

    Create the cart once and retain the returned hc_… bearer capability in secure shopper-session storage. Send it as x-cart-token on later cart calls.

    const created = await fetch('/v1/headless/carts', {
      method: 'POST',
      headers: { 'x-publishable-key': PUBLIC_KEY }
    }).then(r => r.json());
    
    // Keep this bearer capability out of URLs, logs and analytics.
    sessionStorage.setItem('cart_token', created.cartToken);
  3. 3

    Add server-approved products

    Use product and variant IDs returned by the catalog. A product with options needs the chosen variantId. Render the cart projection returned by the API—price, promotion and totals are server-calculated. Never automatically retry mutations after an uncertain network result.

  4. 4

    Prepare checkout

    Save bounded guest contact and addresses with PATCH /v1/headless/carts/current/checkout. Render only returned shipping and checkout-ready payment methods, then persist selections using their returned IDs.

  5. 5

    Place only an approved non-hosted order

    Resolve every field in missing[], then inspect the selected payment method. Only when it explicitly returns requiresHostedCheckout: false and canPlaceOrder: true, call POST /v1/headless/carts/current/checkout/order with a caller-owned Idempotency-Key of 1–120 characters.

    const intent = crypto.randomUUID(); // retain across uncertainty
    const placed = await fetch('/v1/headless/carts/current/checkout/order', {
      method: 'POST',
      headers: {
        'x-publishable-key': PUBLIC_KEY,
        'x-cart-token': CART_TOKEN,
        'Idempotency-Key': intent
      }
    });
  6. 6

    Reconcile uncertainty; never duplicate intent

    If the order response is lost or times out, retry with the same cart token and the exact same idempotency key. A successful response returns a pending order confirmation; it does not authorize or capture payment. Hosted card and wallet methods must use a future hosted flow and are rejected by this command.

Start with your stack

Nine maintained projects, not a locked-in frontend

Prefer a reference project for a specific stack? Each one needs a single store ID, discovers everything else at runtime, and fails closed: configuration or API failures are visible, and no project substitutes synthetic commerce data. Every project runs a live journey against the deployed API in its own CI.

Starter · React + Tailwind

Direct-browser storefront

Bootstraps in the browser from one store ID and completes the capability-gated, idempotent pending-order journey, with an always-available guest order-status form.

Store ID goes in
public/headless-config.json
View repository
Starter · Next.js

Server-side adapter

Bootstraps on the server and exposes only constrained routes, including one allow-listed order-lookup proxy, so it never becomes an open proxy to the API.

Store ID goes in
headless.config.json
View repository
Starter · Angular

Runtime-configured web app

Standalone components and signals. The runtime is bootstrapped before any commerce call and the cart capability is restored from session storage.

Store ID goes in
public/headless-config.json
View repository
Starter · Ionic + Capacitor

Mobile-shaped React app

An Ionic React reference with an order-status card, verified by a live journey in a Pixel 7 browser profile.

Native secure storage, deep links, signing and store submission are not yet qualified.

Store ID goes in
public/headless-config.json
View repository
Starter · Flutter

One codebase for web, Android and iOS

A typed Dart client and native widget UI. The compiled web build creates an order, reloads and reopens it by number and email.

Signed builds, device installation and store submission are not yet qualified.

Store ID goes in
assets/headless-config.json
View repository
Plugin · WordPress

Catalog block and storefront shortcode

A server-side catalog client, a Gutenberg block and an [onecomm_storefront] shortcode for cart, checkout preparation and order lookup. Shopper tokens stay in HttpOnly cookies.

It does not collect payment.

Store ID goes in
the onecomm_store_id setting
View repository
SDK · TypeScript

Typed foundation for browser and server

Catalog, cart, checkout preparation, non-hosted order placement and order lookup. Resolves its API URL and key from one store ID and rejects a mismatched bootstrap.

Store ID goes in
HeadlessCommerceClient.forStore({ storeId })
View repository
SDK · PHP + Laravel

Framework-neutral PHP client

Catalog, cart, checkout and customer operations, with an optional service provider that boots in a real Laravel 12 application. Tested on PHP 8.2–8.4.

Store ID goes in
the client constructor
View repository
SDK · Ruby + Rails

Ruby client with a Railtie

Catalog, cart, checkout and customer operations, with an optional Railtie that boots in a real Rails 7.2 application. Tested on Ruby 3.1–3.4.

Store ID goes in
the client constructor
View repository

Security by design

Public identifiers. Private shopper capabilities.

The store bootstrap returns public values only. Commerce scope is still derived from its configured publishable key, while cart tokens remain bearer credentials. Keep tokens out of URLs, telemetry and unrelated origins. Missing, expired, unknown and cross-store cart tokens share the same not-found response to avoid leaking tenancy.

  • ✓ Store scope derived from the configured key
  • ✓ Strict, bounded checkout fields
  • ✓ Narrow public projections
  • ✓ Stable idempotency key required for order retries

Build beyond the template

Your commerce experience should feel like your business.

Start with the CLI or a maintained starter, prove the live journey, and shape your channel around a single commerce core.