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_ownerorstore_staff(seeStoreAreaControllerBase). - 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+addressAreaIdfrom public address reference API.
Minimum integration checklist
- Login and inspect roles/claims.
- Verify standard endpoint:
GET /api/v1/store/orders
- Verify RBAC endpoint:
GET /api/v1/store/rbac/roles
- Verify permission catalog:
GET /api/v1/store/rbac/permissions
Storefront endpoints
Stores manage a public-facing storefront page from this surface:
| Method | Path | Permission | Notes |
|---|---|---|---|
GET | /api/v1/store/storefront | store.storefront.view | Read current storefront settings + public URL |
PUT | /api/v1/store/storefront | store.storefront.manage | Update description, cover image, niche |
POST | /api/v1/store/storefront/publish | store.storefront.manage | Go live — requires slug assigned |
DELETE | /api/v1/store/storefront/publish | store.storefront.manage | Take offline |
GET | /api/v1/store/storefront/templates | store.storefront.view | List available niche templates |
POST | /api/v1/store/storefront/templates/{id}/apply | store.storefront.manage | Apply 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.
| Method | Path | Permission | Notes |
|---|---|---|---|
GET | /api/v1/store/oauth-mcp/redirect-uris | store.oauth_mcp.redirect_uris.view | Optional ?clientId= filter |
POST | /api/v1/store/oauth-mcp/redirect-uris | store.oauth_mcp.redirect_uris.manage | Body: { clientId, redirectUri } |
DELETE | /api/v1/store/oauth-mcp/redirect-uris/{id} | store.oauth_mcp.redirect_uris.manage | Soft 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_staffrole 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 initems, or missingpayment_method.
E-Commerce Module Base Paths
All routes below are under /api/v1/store/.
| Module | Base Path | View Permission | Manage Permission |
|---|---|---|---|
| Product Categories | categories | store.product_categories.view | store.product_categories.manage |
| Customers | customers | store.customers.view | store.customers.manage |
| Suppliers | suppliers | store.suppliers.view | store.suppliers.manage |
| Purchase Orders | purchase-orders | store.purchase_orders.view | store.purchase_orders.manage |
| Expenses | expenses | store.expenses.view | store.expenses.manage |
| Cashier / POS | cashier | store.cashier.view | store.cashier.manage |
| Discount Rules | discounts/rules | store.discounts.view | store.discounts.manage |
| Discount Codes | discounts/codes | store.discounts.view | store.discounts.manage |
| Shipping Rules | shipping/rules | store.shipping.view | store.shipping.manage |
| Package Sizes | package-sizes | store.package_sizes.view | store.package_sizes.manage |
| Print Templates | print-templates | store.print_templates.view | store.print_templates.manage |
| Store Settings | settings | store.settings.view | store.settings.manage |
| Analytics | analytics | store.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/activereturns the current open session (404 if none).GET /cashier/sessionsreturns 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 valuePOST /analytics/products— top products by quantity and revenuePOST /analytics/customers— customer count, new customers, top spendersPOST /analytics/expenses— total expenses by categoryPOST /analytics/revenue—RevenueDataPoint[]for charting
Source: DOCS/02-clients/store-frontend.md