Authentication

Permissions & Scopes

Roles, permissions, and integration scopes for the Store API.

Store integrations — authentication and scopes

Authentication

ItemValue
HTTP headerX-API-Key — send your integration API key on every request
ASP.NET schemeApiKey
Controller[Authorize(AuthenticationSchemes = "ApiKey")] on StoreIntegrationsController

Unauthenticated or invalid key handling is defined by the host’s API key authentication handler (typically 401).

Address reference (public)

GET /api/v1/address-reference/provinces and GET /api/v1/address-reference/provinces/{code}/areas are AllowAnonymous — no X-API-Key. Same host as your integration; not under /store/integrations. Use them to resolve addressProvinceCode and addressAreaId before POST /orders. Shapes and query params: api-design.jsonaddressReference.

Scopes

  • Scopes are read from the scope claim on the authenticated principal.

  • If the required scope for an action is missing, the API returns 403 with body:

    ApiResponse with success: false, message: Missing scope: <scope>, and code: 403.

Scopes by area

The entire Store surface is now available under /api/v1/store/integrations with an X-API-Key. Each endpoint requires the resource scope below; missing the scope returns 403. Grant a key only the scopes it needs (least privilege) — …:read for GET, …:write for create/update/delete.

ScopeArea / use
orders:read / orders:writeOrders, order items, returns, status, QR, storefront OTP, delivery companies
catalog:read / catalog:writeProducts, product categories, inventory, warehouses, package sizes
purchasing:read / purchasing:writeSuppliers, purchase orders (and attachments)
customers:read / customers:writeCustomer (CRM) records
discounts:read / discounts:writeDiscount codes (+ validate) and discount rules
finance:read / finance:writeExpenses, wallet balance/transactions/bank details
analytics:readSales/product/customer/expense/revenue analytics, dashboard summaries
printing:read / printing:writeInvoice & label print templates
store:read / store:writeSettings, profile, storefront (publish, templates, custom domain, sections, images)
pos:read / pos:writeCashier settings, sessions, pinned items
tickets:read / tickets:writeSupport tickets
messaging:read / messaging:writeWebsite-chat hub token + conversations; social inbox conversations & channels
delivery:read / delivery:writeDelivery providers, Al-Waseet, Boxy (orders, pickups, locations)
subscription:read / subscription:writeSubscription, available plans, upgrade requests
kyc:writeUpload KYC documents
rbac:read / rbac:writeStaff users, roles, permissions (RBAC)
apikeys:read / apikeys:writeList / create / revoke API keys
mcp:read / mcp:writeMCP integration info, OAuth redirect URIs

Security note: rbac:*, apikeys:*, kyc:write, and subscription:write are powerful account-management scopes — only grant them to keys you fully trust, and prefer separate keys per integration.

Store JWT permissions (storefront)

Storefront endpoints use JWT bearer (not X-API-Key) with the following permission gates:

PermissionRoutes
store.storefront.viewGET /api/v1/store/storefront, GET /api/v1/store/storefront/templates
store.storefront.managePUT /api/v1/store/storefront, publish/unpublish, apply template

Both permissions are granted to store_owner by default. store_staff receives store.storefront.view only.

Public storefront (no auth)

GET /api/v1/public/storefronts/{slug} and POST /api/v1/public/storefronts/{slug}/orders are [AllowAnonymous] — no X-API-Key or JWT. The store must have IsStorefrontPublished = true for these to return data (otherwise 404).

Response envelope

All integration actions return ApiResponse<T> in JSON:

  • successtrue on success.
  • data — typed payload (see dtos, addressReference, and endpoints in api-design.json).
  • message — human-readable summary (optional on success, useful on errors).
  • code — on errors, mirrors HTTP semantics (400, 401, 403, 404, 409, 422, 429, 500).
  • errors — on validation failure, object map of field name → string[] messages.

HTTP status is chosen with RespondByErrorCode: success responses use 200; errors use the status matching code when present. Model binding / FluentValidation failures return 400 with ApiResponse and errors populated.

Linking

If the API key is not linked to a Store, many calls return 400 with a message such as "No store linked to this API key" (see StoreIntegrationsService).

Internal tenant claim (JWT and API keys)

For password/JWT users and store- or delivery-company-scoped API keys, the server may issue an internal claim organization_id (UUID) used for database row scoping. It is not required for integration clients to send this claim; it is derived from the authenticated store or delivery company. Platform admin and similar roles do not use this filter.


Store E-Commerce Module Permissions (JWT)

All permissions below apply to store JWT endpoints under /api/v1/store/*.

PermissionWhat it gatesstore_ownerstore_staff
store.product_categories.viewGET /categories, GET /categories/{id}
store.product_categories.managePOST/PUT/DELETE /categories
store.customers.viewGET /customers, GET /customers/{id}
store.customers.managePOST/PUT/DELETE /customers
store.suppliers.viewGET /suppliers, GET /suppliers/{id}
store.suppliers.managePOST/PUT/DELETE /suppliers
store.purchase_orders.viewGET /purchase-orders, GET /purchase-orders/{id}
store.purchase_orders.managePOST/PUT/DELETE /purchase-orders, attachments
store.expenses.viewGET /expenses, GET /expenses/{id}
store.expenses.managePOST/PUT/DELETE /expenses
store.cashier.viewGET /cashier/settings, sessions, pinned items
store.cashier.managePUT /cashier/settings, open/close sessions, pin items
store.discounts.viewGET /discounts/rules, GET /discounts/codes, validate
store.discounts.managePOST/PUT/DELETE /discounts/rules, codes
store.shipping.viewGET /shipping/rules, GET /shipping/rules/{id}
store.shipping.managePOST/PUT/DELETE /shipping/rules
store.package_sizes.viewGET /package-sizes, GET /package-sizes/{id}
store.package_sizes.managePOST/PUT/DELETE /package-sizes
store.print_templates.viewGET /print-templates, GET /print-templates/{id}
store.print_templates.managePOST/PUT/DELETE /print-templates
store.settings.viewGET /settings
store.settings.managePOST /settings (init), PUT /settings
store.analytics.viewAll POST /analytics/* endpoints

store_staff summary: receives all *.view permissions + store.customers.manage + store.cashier.manage + store.analytics.view.


Social Messaging Permissions (JWT)

Permissions for the Social Messaging / CRM feature under /api/v1/store/social/*.

PermissionWhat it gatesstore_ownerstore_staff
store.social_channels.viewGET /social/channels
store.social_channels.managePOST/PATCH/DELETE /social/channels, toggle-agent, rotate-token
store.conversations.viewGET /social/conversations, GET /social/conversations/{id}
store.conversations.managePOST /messages, resolve, reopen

store_staff can read and reply to conversations but cannot connect, disconnect, or reconfigure channels.

MCP OAuth Scopes for Social Messaging

ScopeMCP tools that require it
messaging:readlist_conversations, get_conversation
messaging:writesend_conversation_message, resolve_conversation

These scopes are issued via the standard OAuth 2.0 PKCE flow (see store-mcp-server.md).

Source: DOCS/03-integrations/specs/store/auth-and-scopes.md