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.md → OTP 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.md → Website Chat (Integration).
Contract notes
- Address linkage required in create/bulk order flows:
addressProvinceCodeaddressAreaId
fulfillmentTypevalues arefrom_toorwarehouse.
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/ticketsGET /api/v1/store/tickets/{ticketId}POST /api/v1/store/ticketsPUT /api/v1/store/tickets/{ticketId}DELETE /api/v1/store/tickets/{ticketId}(soft delete)
Ownership and scoping
- Requests are scoped to
OwnerType=Store. OwnerIdis derived from authenticatedcurrent.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— initializecurrencyCode,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/categoriesPOST /api/v1/store/categoriesPUT /api/v1/store/categories/{id}DELETE /api/v1/store/categories/{id}— blocked if subcategories or products exist.
Customers
GET /api/v1/store/customers?search=—searchfilters name, phone, email.POST /api/v1/store/customers—primaryPhonemust 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 computestotalAmount.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/settingsGET /api/v1/store/cashier/sessions,GET /api/v1/store/cashier/sessions/activePOST /api/v1/store/cashier/sessions/open— 409 if session already open.POST /api/v1/store/cashier/sessions/{id}/closeGET/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/rulesGET/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-sizes—isDefault: trueclears previous default.
Print templates
GET /api/v1/store/print-templates?type=(optional filter byInvoice/ShippingLabel/Receipt)POST/PUT/DELETE /api/v1/store/print-templates
Analytics
All use POST with body { from, to, granularity? }:
POST /api/v1/store/analytics/salesPOST /api/v1/store/analytics/productsPOST /api/v1/store/analytics/customersPOST /api/v1/store/analytics/expensesPOST /api/v1/store/analytics/revenue
Full permission table: DOCS/03-integrations/specs/store/auth-and-scopes.md.
Order Create: New Validations
payment_methodis required — omitting it returns 400.- Duplicate SKUs in
itemsare rejected with 400 and askuserror field listing the duplicates. delivery_latanddelivery_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,priorityare now enums (serialized as string names by default). payment_methodis 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