# ShasPOS Pro API v1

Base path: `/api/v1`

## Headers
- `Authorization: Bearer <access-token>`
- `X-Business-Id: <business-ulid>` after business selection
- `X-Outlet-Id: <outlet-ulid>` when outlet context is required
- `Idempotency-Key: <unique-key>` on financial/stock posting mutations
- `X-Client-Platform`, `X-App-Version`, `X-Device-Id`

HTTPS and JSON are mandatory in production.

## Standard success
```json
{"success":true,"data":{},"meta":{"request_id":"01..."}}
```

## Standard error
```json
{
  "success":false,
  "error":{"code":"INSUFFICIENT_STOCK","message":"Insufficient stock.","fields":{}},
  "meta":{"request_id":"01..."}
}
```

## Status codes
`200/201` success, `204` no-content success, `400` malformed, `401` unauthenticated, `403` unauthorized/plan-disabled, `404` tenant-scoped not found, `409` version/idempotency/workflow conflict, `422` validation/business rule, `429` rate limit, `500` masked server error, `503` temporary unavailable.

## Pagination
`page` + `per_page`; default 25, maximum 100. Meta returns page/per_page/total/last_page.

## Route catalog

### Auth
`POST /auth/register`
`POST /auth/verify-email`
`POST /auth/login`
`POST /auth/refresh`
`POST /auth/logout`
`POST /auth/logout-all`
`POST /auth/forgot-password`
`POST /auth/reset-password`
`GET/PATCH /me`

### Tenancy
`GET/POST /businesses`
`GET/PATCH /businesses/{business}`
`GET/POST /outlets`
`GET/PATCH /outlets/{outlet}`
`GET /devices`
`POST /devices/register`
`DELETE /devices/{device}`

### Staff/RBAC
`GET/POST /staff`
`GET/PATCH /staff/{staff}`
`GET/POST /roles`
`PATCH /roles/{role}`
`GET /permissions`
`PUT /roles/{role}/permissions`
`PUT /staff/{staff}/permission-overrides`
`GET /approval-rules`
`PUT /approval-rules/{rule}`

### Subscription/Billing
`GET /plans`
`GET /subscription`
`POST /subscription/trial`
`POST /subscription/change-plan`
`POST /subscription/cancel`
`POST /subscription/resume`
`GET /billing/invoices`
`GET /billing/invoices/{invoice}`
`GET /billing/gateways`
`POST /billing/invoices/{invoice}/checkout` — idempotent
`GET /billing/payment-attempts/{attempt}`
`POST /webhooks/shaspay` — public, signature authenticated

### Catalog
`GET/POST /categories`
`GET/PATCH/DELETE /categories/{category}`
`GET/POST /units`
`GET/PATCH /units/{unit}`
`GET/POST /tax-rates`
`GET/PATCH /tax-rates/{taxRate}`
`GET/POST /payment-methods`
`GET/PATCH /payment-methods/{paymentMethod}`
`GET/POST /products`
`GET/PATCH/DELETE /products/{product}`
`GET /products/by-barcode/{barcode}`
`POST /products/import`
`GET /products/export`

### Customers/Suppliers
`GET/POST /customers`
`GET/PATCH /customers/{customer}`
`GET /customers/{customer}/ledger`
`POST /customers/{customer}/payments` — idempotent
`GET/POST /suppliers`
`GET/PATCH /suppliers/{supplier}`
`GET /suppliers/{supplier}/ledger`
`POST /suppliers/{supplier}/payments` — idempotent

### Inventory
`GET /inventory/stock`
`GET /inventory/movements`
`GET/POST /inventory/locations`
`GET /inventory/batches`
`POST /inventory/adjustments`
`POST /inventory/adjustments/{id}/submit`
`POST /inventory/adjustments/{id}/approve`
`POST /inventory/adjustments/{id}/post` — idempotent
`GET/POST /inventory/transfers`
`POST /inventory/transfers/{id}/dispatch`
`POST /inventory/transfers/{id}/receive` — idempotent
`GET/POST /stock-takes`
`PUT /stock-takes/{id}/counts`
`POST /stock-takes/{id}/submit`
`POST /stock-takes/{id}/approve`
`POST /stock-takes/{id}/post` — idempotent

### Sales/Returns
`POST /sales/quote` — server preview only
`POST /sales` — idempotent + atomic
`GET /sales`
`GET /sales/{sale}`
`POST /sales/{sale}/void`
`POST /sales/{sale}/payments`
`GET /returns`
`POST /returns` — idempotent + atomic
`GET /returns/{return}`

### Cash Register
`GET/POST /cash-registers`
`GET /cash-sessions`
`POST /cash-sessions/open`
`POST /cash-sessions/{id}/movement`
`POST /cash-sessions/{id}/close`
`POST /cash-sessions/{id}/approve-variance`

### Purchasing
`GET/POST /purchases`
`GET /purchases/{purchase}`
`GET/POST /purchase-orders`
`GET/PATCH /purchase-orders/{po}`
`POST /purchase-orders/{po}/submit`
`POST /purchase-orders/{po}/approve`
`POST /purchase-orders/{po}/cancel`
`POST /purchase-orders/{po}/receive` — idempotent + atomic
`GET /goods-receipts`
`GET /goods-receipts/{grn}`

### Finance/Reports
`GET/POST /financial-accounts`
`GET /financial-accounts/{account}/ledger`
`GET/POST /income`
`GET/POST /expenses`
`GET /reports/dashboard`
`GET /reports/sales-summary`
`GET /reports/inventory-valuation`
`GET /reports/profit`
`GET /reports/customer-aging`
`GET /reports/supplier-aging`
`POST /reports/export`

### Audit/Notifications
`GET /audit-logs`
`GET /notifications`
`POST /notifications/{id}/read`

## Sale posting rule
The request may contain intended price/discount/payment values, but the server reloads products, price permissions, stock, batch rules, taxes, customer credit, cash session and subscription entitlement; then it recalculates and posts atomically.
