Authentication

API Key Authentication

Issue API keys and authenticate server-to-server integrations.

Store Integration Guide

API-Key Surface

Base route

  • /api/v1/store/integrations/*

Required headers

  • X-API-Key: <keyId.secret>
  • Content-Type: application/json (for body requests)

Scope expectations

  • Orders: orders:read, orders:write
  • Catalog/inventory: catalog:read, catalog:write
  • Website chat: messaging:read, messaging:write

New: OTP-verified storefront orders

POST /orders/send-otp (scope orders:write) sends an OTP to a customer phone. Pass the returned code as otpCode in POST /orders/storefront to create an OTP-verified order. See specs/store/endpoints.mdOTP for Storefront Orders.

New: Website Chat via API key

REST endpoints at /chat/conversations/** (scopes messaging:read/messaging:write) mirror the dashboard inbox for programmatic bots or CRM sync. Real-time events are available via SignalR at wss://{host}/hubs/store-conversations using a short-lived hub token (exchange via POST /chat/hub-token, then call JoinStore(token)) — the raw API key never appears in a URL or WebSocket frame. See specs/store/endpoints.mdWebsite Chat (Integration).

Contract notes

  • Address linkage required in create/bulk order flows:
    • addressProvinceCode
    • addressAreaId
  • fulfillmentType values are from_to or warehouse.

Store JWT Tickets CRUD Surface

These endpoints are JWT role/permission based (not API-key based).

Base route

  • /api/v1/store/tickets

Endpoints

  • GET /api/v1/store/tickets
  • GET /api/v1/store/tickets/{ticketId}
  • POST /api/v1/store/tickets
  • PUT /api/v1/store/tickets/{ticketId}
  • DELETE /api/v1/store/tickets/{ticketId} (soft delete)

Ownership and scoping

  • Requests are scoped to OwnerType=Store.
  • OwnerId is derived from authenticated current.StoreId.
  • Incoming payload cannot override owner context.

Create payload (example)

{
  "subject": "Stock mismatch for order ORD-123",
  "status": "open",
  "priority": "high",
  "category": "inventory",
  "assignedUserId": "00000000-0000-0000-0000-000000000000"
}

Store JWT E-Commerce Modules

These endpoints use JWT bearer (not API-key) and are accessible to store_owner / store_staff.

Settings (initialize first)

  • POST /api/v1/store/settings — initialize currencyCode, timezone, industry, countryCode (call once per store). Returns 409 if already set.
  • GET /api/v1/store/settings — read current settings.
  • PUT /api/v1/store/settings — update settings.

Product categories

  • GET /api/v1/store/categories
  • POST /api/v1/store/categories
  • PUT /api/v1/store/categories/{id}
  • DELETE /api/v1/store/categories/{id} — blocked if subcategories or products exist.

Customers

  • GET /api/v1/store/customers?search=search filters name, phone, email.
  • POST /api/v1/store/customersprimaryPhone must be unique per store (409 on dup).

Suppliers

  • GET/POST/PUT/DELETE /api/v1/store/suppliers

Purchase orders

  • GET/POST/PUT/DELETE /api/v1/store/purchase-orders — min 1 item on create; server computes totalAmount.
  • POST /api/v1/store/purchase-orders/{id}/attachments — max 3 attachments (400 if exceeded).
  • DELETE /api/v1/store/purchase-orders/{id}/attachments/{attachmentId}

Expenses

  • GET /api/v1/store/expenses?from=&to=&category=
  • POST/PUT/DELETE /api/v1/store/expenses

Cashier / POS

  • GET/PUT /api/v1/store/cashier/settings
  • GET /api/v1/store/cashier/sessions, GET /api/v1/store/cashier/sessions/active
  • POST /api/v1/store/cashier/sessions/open — 409 if session already open.
  • POST /api/v1/store/cashier/sessions/{id}/close
  • GET/POST /api/v1/store/cashier/pinned — max 30 pinned items.
  • DELETE /api/v1/store/cashier/pinned/{productId}
  • PUT /api/v1/store/cashier/pinned/reorder

Discounts

  • GET/POST/PUT/DELETE /api/v1/store/discounts/rules
  • GET/POST/PUT/DELETE /api/v1/store/discounts/codes — code normalized to uppercase; percentage must be 0–100; expiresAt must be after startsAt.
  • GET /api/v1/store/discounts/codes/validate?code=&orderValue=

Shipping rules

  • GET/POST/PUT/DELETE /api/v1/store/shipping/rules

Package sizes

  • GET/POST/PUT/DELETE /api/v1/store/package-sizesisDefault: true clears previous default.
  • GET /api/v1/store/print-templates?type= (optional filter by Invoice/ShippingLabel/Receipt)
  • POST/PUT/DELETE /api/v1/store/print-templates

Analytics

All use POST with body { from, to, granularity? }:

  • POST /api/v1/store/analytics/sales
  • POST /api/v1/store/analytics/products
  • POST /api/v1/store/analytics/customers
  • POST /api/v1/store/analytics/expenses
  • POST /api/v1/store/analytics/revenue

Full permission table: DOCS/03-integrations/specs/store/auth-and-scopes.md.

Order Create: New Validations

  • payment_method is required — omitting it returns 400.
  • Duplicate SKUs in items are rejected with 400 and a skus error field listing the duplicates.
  • delivery_lat and delivery_lng (optional decimal) can now be sent and are returned in list/detail responses.

Breaking Change Notes (Phase-2)

  • FlowApp is fully removed. Use Nawa:* config and /api/v1/integrations/nawa/webhooks.
  • Ticket status, category, priority are now enums (serialized as string names by default).
  • payment_method is now required on order create.
  • MCP endpoints use OAuth 2.0 bearer — see store-mcp-server.md.

Source: DOCS/03-integrations/store-api-key.md