mock-helix

The Mock Server

A local HTTP service that impersonates the Helix public API. Same endpoints, same OAuth flow, same JSON shapes — backed by an in-memory store instead of the real Helix database. Build and test integrations without touching production or needing credentials.

Quickstart Endpoints
๐Ÿงช

Reproducible seeds

Every run starts from the same in-memory fixtures: brands, categories, terminals, products, inventory. Tests are deterministic.

๐Ÿ”

Same contract as prod

Implements the OpenAPI contract at openapi/helix-sandbox.yaml. Code written against the mock works against real Helix.

๐Ÿšซ

Not for production

Tokens are stored in a Map, nothing is persisted, and writes are gated by an env flag. Local dev / CI only.

Quickstart

Three ways to run it. Pick one.

1 Docker Compose (recommended)

From the helix-toolkit repo root. Also starts the sample app.

# In helix-toolkit/
docker compose up mock-helix

# Or the whole stack (mock-helix + sample-app)
docker compose up

2 Toolkit CLI

helix-toolkit mock start

3 Node directly

# In helix-toolkit/mock-helix/
npm install
HELIX_MOCK_PORT=47100 node server.js

โœ“ Smoke test

Confirm it's up:

curl http://127.0.0.1:47100/health
# โ†’ {"status":"ok","service":"mock-helix"}

Auth Flow

The mock speaks OAuth2 client-credentials. Exchange a client id for a Bearer token, then call /api/v1/* with it.

# 1. Get a token (any client_id works on the mock)
curl -s -X POST http://127.0.0.1:47100/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=sandbox-client"
# โ†’ {"access_token":"mock_at_...","token_type":"Bearer","expires_in":3600}

# 2. Call an authenticated endpoint
curl -s http://127.0.0.1:47100/api/v1/tenant \
  -H "Authorization: Bearer mock_at_..."

Tokens live in memory for the lifetime of the process. Restart the server and existing tokens stop working.

Endpoints

All /api/v1/* paths require a Bearer token.

Discovery & Auth

Method Path Description
GET/healthLiveness (unauthenticated)
GET/.well-known/helix-sandboxIssuer, token endpoint, API base
POST/oauth/tokenclient_credentials or authorization_code

Core Data

Method Path Description
GET/api/v1/meCurrent principal
GET/api/v1/tenantTenant summary
GET/api/v1/integrationsPaginated list (limit, cursor)
GET/api/v1/integrations/{id}Single integration
POST/api/v1/integrationsCreate (gated โ€” see Writes)
GET/api/v1/pingAuthenticated ping
POST/api/v1/echoEchoes JSON body

Helix Apps SDK

The surface that embedded iframe apps call via helix.apiGet(...). The SDK prefixes /api automatically — you pass /stores, the request hits /api/stores on the mock.

Method Path Description
GET/api/storesList stores
GET/api/store_statsStore sales, transactions, labor (filter ?store_id=)
GET/api/store_stats/transactionsTransaction rows (filter ?store_id=)
GET/api/kra/day_dataKRA daily metrics (filter ?store_id=, ?date=)
GET/api/kra/storesActive stores for KRA dashboards
GET/api/kra/blocksKRA data-block definitions
GET/api/kra/transactionsKRA-filtered transactions
GET/api/employee_statsPer-employee performance (filter ?store_id=)
GET/api/distribution_productsDistribution product catalog
GET/api/idr_reportsIDR report data
GET/api/auth/authenticateCurrent user info and roles

Blaze Store Inventory

Mirrors Blaze partner /store/inventory/... under the blaze namespace so Blaze client code works unchanged.

Method Path Description
GET/api/v1/blaze/inventory/brandsList brands
GET/api/v1/blaze/inventory/categoriesList categories
GET/api/v1/blaze/inventory/inventoriesStock rows (product ร— terminal)
GET/api/v1/blaze/inventory/productsList products
GET/api/v1/blaze/inventory/products/{productId}Product by id
GET/api/v1/blaze/inventory/products/datesProducts where modified_at > ?modified_after=
GET/api/v1/blaze/inventory/products/terminals/{terminalId}Products at a terminal with on-hand quantity
GET/api/v1/blaze/inventory/sku/{sku}Product by SKU with per-terminal quantities
GET/api/v1/blaze/inventory/terminalsList terminals

Seed Data

Each tenant gets the same fixtures on first request. Writes persist in-memory for the process lifetime.

Integrations (2)

  • int_sandbox_primary — active
  • int_sandbox_secondary — paused

Brands (2)

  • brnd_sandbox_alpha
  • brnd_sandbox_bravo

Categories (3)

  • cat_flower, cat_edibles, cat_prerolls

Terminals (2)

  • term_front, term_back

Products (3) & Inventory (5 rows)

  • prod_alpha_eighth — SKU-ALPHA-8TH — 42 @ term_front, 18 @ term_back
  • prod_bravo_gummies — SKU-BRAVO-GUM10 — 120 @ term_front
  • prod_alpha_preroll — SKU-ALPHA-PR1G — 8 @ term_front, 0 @ term_back

Environment Variables

Variable Default Purpose
HELIX_MOCK_PORT47100HTTP listen port
MOCK_TENANT_IDtenant-sandbox-001Tenant id stamped onto issued tokens
HELIX_MOCK_ALLOW_WRITE(unset)Set to 1 to allow POST /api/v1/integrations. Otherwise returns 403 write_forbidden.

Writes Are Gated

By default, write endpoints return 403 write_forbidden — the same error shape real Helix sends when your integration lacks the scope. This catches scope mistakes early.

# Read-only (default) — POST fails
docker compose up mock-helix

# Enable writes
HELIX_MOCK_ALLOW_WRITE=1 docker compose up mock-helix

# Or in docker-compose.yml
environment:
  - HELIX_MOCK_ALLOW_WRITE=1

Calling the Mock

You don't have to hand-craft requests. The toolkit ships clients that point at the mock by default.

Node SDK (sample-app)

const { createHelixDataClient } = require('./sample-app/src/lib/helixData');

const client = createHelixDataClient({
  baseUrl: 'http://127.0.0.1:47100',
  getAccessToken: async () => '<token from /oauth/token>',
});

await client.pull.tenant();
await client.pull.blaze.products({ limit: 10 });
await client.pull.blaze.sku('SKU-ALPHA-8TH');

MCP server

Expose the mock as tools to Claude, Cursor, or any MCP-aware agent. Set HELIX_API_BASE_URL to the mock's URL and the MCP wraps every endpoint as a tool.

# From helix-toolkit/mcp-helix
HELIX_API_BASE_URL=http://127.0.0.1:47100 node src/server.js

# Available tools include:
# helix.pull.me, helix.pull.tenant, helix.pull.integrations
# helix.blaze.brands, helix.blaze.products, helix.blaze.sku, ...

OpenAPI spec

The full contract lives at helix-toolkit/openapi/helix-sandbox.yaml. Feed it to code generators, Postman, or the MCP server (exposed as resource helix://sandbox/openapi.yaml).