Getting Started

Store Frontend (JWT)

Building a store dashboard frontend with JWT bearer auth.

Store Frontend Integration

Surface

  • Base route: /api/v1/store/*
  • Primary source: Sendy.Api/Controllers/V1/Store/*

Auth requirements

  • JWT bearer token required.
  • Role gate: store_owner or store_staff (see StoreAreaControllerBase).
  • Permission gate: store.* permissions per endpoint.
  • Store RBAC endpoints require: store.rbac.manage.

Critical details

  • Role gate and permission gate are both enforced.
  • After role/permission changes, client should re-login to refresh token claims.
  • Address-based order flows require addressProvinceCode + addressAreaId from public address reference API.

Minimum integration checklist

  1. Login and inspect roles/claims.
  2. Verify standard endpoint:
    • GET /api/v1/store/orders
  3. Verify RBAC endpoint:
    • GET /api/v1/store/rbac/roles
  4. Verify permission catalog:
    • GET /api/v1/store/rbac/permissions

Storefront endpoints

Stores manage a public-facing storefront page from this surface:

MethodPathPermissionNotes
GET/api/v1/store/storefrontstore.storefront.viewRead current storefront settings + public URL
PUT/api/v1/store/storefrontstore.storefront.manageUpdate description, cover image, niche
POST/api/v1/store/storefront/publishstore.storefront.manageGo live — requires slug assigned
DELETE/api/v1/store/storefront/publishstore.storefront.manageTake offline
GET/api/v1/store/storefront/templatesstore.storefront.viewList available niche templates
POST/api/v1/store/storefront/templates/{id}/applystore.storefront.manageApply template (sets niche + theme)

store_owner has both store.storefront.view and store.storefront.manage by default. store_staff has store.storefront.view only.

The public customer-facing URL (publicUrl in the response) is [AllowAnonymous] and lives under /api/v1/public/storefronts/{slug} — it is not a store JWT endpoint.

MCP OAuth Redirect URI Management

Stores can register allowed redirect URIs so that MCP clients (Cursor, Claude Desktop, custom agents) can complete the OAuth flow.

MethodPathPermissionNotes
GET/api/v1/store/oauth-mcp/redirect-urisstore.oauth_mcp.redirect_uris.viewOptional ?clientId= filter
POST/api/v1/store/oauth-mcp/redirect-urisstore.oauth_mcp.redirect_uris.manageBody: { clientId, redirectUri }
DELETE/api/v1/store/oauth-mcp/redirect-uris/{id}store.oauth_mcp.redirect_uris.manageSoft delete

store_owner and store_staff both have both permissions by default.

Order Coordinates

delivery_lat and delivery_lng are now returned in GET /api/v1/store/orders list items and order detail responses. These fields are nullable floats.

Common failure patterns

  • 403 on all store endpoints: missing store_owner/store_staff role claim.
  • 403 only on RBAC endpoints: missing store.rbac.manage.
  • 400 on POST /storefront/publish: store has no slug assigned — contact admin to provision one.
  • 400 on POST /api/v1/store/orders (or integration orders): duplicate SKUs in items, or missing payment_method.

E-Commerce Module Base Paths

All routes below are under /api/v1/store/.

ModuleBase PathView PermissionManage Permission
Product Categoriescategoriesstore.product_categories.viewstore.product_categories.manage
Customerscustomersstore.customers.viewstore.customers.manage
Supplierssuppliersstore.suppliers.viewstore.suppliers.manage
Purchase Orderspurchase-ordersstore.purchase_orders.viewstore.purchase_orders.manage
Expensesexpensesstore.expenses.viewstore.expenses.manage
Cashier / POScashierstore.cashier.viewstore.cashier.manage
Discount Rulesdiscounts/rulesstore.discounts.viewstore.discounts.manage
Discount Codesdiscounts/codesstore.discounts.viewstore.discounts.manage
Shipping Rulesshipping/rulesstore.shipping.viewstore.shipping.manage
Package Sizespackage-sizesstore.package_sizes.viewstore.package_sizes.manage
Print Templatesprint-templatesstore.print_templates.viewstore.print_templates.manage
Store Settingssettingsstore.settings.viewstore.settings.manage
Analyticsanalyticsstore.analytics.view

Settings Initialization

POST /api/v1/store/settings must be called once after store creation (before most e-commerce features are usable). It accepts currencyCode, timezone, industry, countryCode. Returns 409 if settings already exist — subsequent changes use PUT /api/v1/store/settings.

POS Session Lifecycle

Open Session (POST /cashier/sessions/open)
  → [sell orders during session]
  → Close Session (POST /cashier/sessions/{id}/close)
  • Only one session can be open at a time per store. Opening a second returns 409.
  • GET /cashier/sessions/active returns the current open session (404 if none).
  • GET /cashier/sessions returns all sessions (history).

Analytics Date Range Format

All analytics endpoints use POST with an AnalyticsDateRangeRequest body:

{
  "from": "2026-01-01T00:00:00Z",
  "to": "2026-05-31T23:59:59Z",
  "granularity": "Monthly"
}

granularity values: Daily, Weekly, Monthly. Omit for aggregated totals only.

Available analytics endpoints:

  • POST /analytics/sales — revenue, orders, average order value
  • POST /analytics/products — top products by quantity and revenue
  • POST /analytics/customers — customer count, new customers, top spenders
  • POST /analytics/expenses — total expenses by category
  • POST /analytics/revenueRevenueDataPoint[] for charting

Source: DOCS/02-clients/store-frontend.md