# Backend API Requirements — Merchant Web Console **Audience:** Backend team. **Purpose:** These are the endpoints the merchant web app needs before it can go to staging with zero mock data. Every UI spot listed below currently renders an explicit `Awaiting backend API [Rxx]` placeholder (or a known-wrong stand-in like the `delivered × 355` revenue) until the matching endpoint ships. ## Conventions (match the existing live API) - **Base / proxy:** Fiesta REST at `https://fiesta.nearle.app/live/api/v1/web//`. The frontend calls it through the dev proxy as `/fiesta/live/api/v1/web/...`. - **Auth:** same as current read endpoints (no extra header required for GETs). - **Envelope:** every response is ```json { "code": 200, "status": true, "message": "OK", "details": } ``` `details` is the documented payload (array or object). On failure return `{ "code": 4xx, "status": false, "message": "" }`. - **Types:** money = INR as a plain 2-dp number (e.g. `442800.00`), no currency symbol/string. Dates = `YYYY-MM-DD`. Timestamps = ISO-8601 (`2026-06-06T14:21:00`). Ids = integers. - **Tenant scope (current):** `tenantid=1087`, `applocationid=1`, primary `locationid=1097`. - **Paging:** where listed, accept `pageno` (1-based) and `pagesize`. ## Index | Id | Endpoint | Method | Powers (UI) | Priority | |---|---|---|---|---| | [R1] | `/orders/getrevenuesummary` | GET | Revenue KPIs, OTIF, leaderboard, fulfilment health | **P0** | | [R2] | `/orders/gettimeseries` | GET | Reports main chart, 7-day ledger | **P0** | | [R3] | `/products/getproductanalytics` | GET | Product matrix sales + per-product detail | **P0** | | [R4] | `/imports/getimportlogs` (+ `/imports/upload`) | GET/POST | Import audit stream + validator | P1 | | [R5] | `/products/getcatalogpresets` | GET | Inventory catalog presets (optional) | P2 | | [R6] | `/tenants/getsettings` (+ `/tenants/updatesettings`) | GET/PUT | Settings + Brand studio | P1 | | [R7] | `/insights/getforecast` | GET | Operations forecast tiles (optional) | P2 | | [R8] | `/products/stocktransfer` | POST | Operations stock-transfer modal | P1 | | [R9] | `/partners/getridertelemetry` | GET | Fleet rating, GPS, ETA | P1 | | [R10] | `/deliveries/getdispatchbuckets` | GET | StoreDetail intraday dispatch | P1 | | [R11] | `/customers/getcustomeranalytics` | GET | Customer CSAT/AOV/retention | P1 | | [R12] | `/alerts/getalerts` | GET | Operational alerts feed | P1 | | [R13] | `/reports/getschedules` (+ POST) | GET/POST | Scheduled reports (optional) | P2 | Plus **mutation routes** already named in the endpoint sheet but not yet shape-documented — see the last section. --- ## [R1] Revenue summary · `GET /orders/getrevenuesummary` Real money totals. Today the app fakes revenue as `delivered × 355` — replace that. **Request (query params)** | param | type | required | notes | |---|---|---|---| | `tenantid` | int | ✓ | | | `locationid` | int | | omit → all outlets (overall); set → store-wise | | `fromdate` | date | ✓ | | | `todate` | date | ✓ | | **Response `details`** (single object) ```json { "tenantid": 1087, "locationid": null, "grossrevenue": 1248302.00, "netrevenue": 1180500.00, "profit": 354216.00, "marginpct": 28.4, "ordercount": 4921, "deliveredcount": 4102, "cancelledcount": 142, "otifpct": 98.2, "avgordervalue": 1580.00, "prev_grossrevenue": 1090000.00, "prev_ordercount": 4370 } ``` `prev_*` = same metric for the immediately preceding equal-length window (lets the UI show `+14.2%` deltas without a second call). `otifpct` powers the OTIF / fulfilment-health tiles. Frontend hook to add: `useFiestaRevenueSummary`. --- ## [R2] Orders / revenue time-series · `GET /orders/gettimeseries` Powers the Reports main chart (Orders / Revenue / Cancelled / SKUs) and StoreDetail 7-day ledger. **Request** | param | type | required | notes | |---|---|---|---| | `tenantid` | int | ✓ | | | `locationid` | int | | omit → overall | | `granularity` | enum | ✓ | `day` \| `month` \| `year` | | `fromdate` | date | ✓ | | | `todate` | date | ✓ | | **Response `details`** (array, one bucket per period) ```json [ { "label": "2026-06-01", "orders": 312, "revenue": 442800.00, "delivered": 298, "cancelled": 9, "activeskus": 72 } ] ``` `label` = `YYYY-MM-DD` (day), `YYYY-MM` (month), or `YYYY` (year). Removes all hardcoded chart arrays and the region-scaling multipliers (filter by `locationid` instead). Frontend hook: `useFiestaTimeSeries`. --- ## [R3] Product sales analytics · `GET /products/getproductanalytics` True units-sold + revenue per product, plus the per-product/per-outlet detail the matrix expands. **Request** | param | type | required | notes | |---|---|---|---| | `tenantid` | int | ✓ | | | `locationid` | int | | omit → across all outlets | | `subcategoryid` | int | | | | `fromdate` / `todate` | date | | sales window (default month-to-date) | | `keyword` | string | | | | `pageno` / `pagesize` | int | | | **Response `details`** (array) ```json [ { "productid": 88231, "productname": "Ponni Raw Rice 10kg", "sku": "PONNI-RICE-10K", "categoryid": 2, "subcategoryname": "Rice", "image": "https://…", "unitssold": 12402, "revenue": 868140.00, "trend": "up", "closingstock": 1402, "maxcapacity": 2000, "binlocation": "BIN-C12", "lastauditdate": "2026-06-05", "verified": true, "outlets": [ { "locationid": 1097, "locationname": "RS Puram", "stock": 840 } ] } ] ``` `trend` ∈ `up|flat|down`. `outlets[]` = real per-hub split (replaces hardcoded 60/40). If the catalog doesn't track `binlocation`/`lastauditdate`, return `null` — the UI will hide them rather than fake them. Frontend hook: `useFiestaProductAnalytics`. --- ## [R4] Import / sync audit log · `GET /imports/getimportlogs` + `POST /imports/upload` Replaces the mock "Live Sync Audit Stream" and the hardcoded "14 duplicate SKUs" validator. **GET request:** `tenantid` (✓), `pageno`, `pagesize`. **GET `details`** ```json [ { "importid": 921, "batchref": "#IMP_0921_A", "type": "Inventory Sync", "source": "ERP Export", "rows": 421, "result": "SUCCESS", "message": "421 rows imported", "createdat": "2026-05-31T09:12:00" } ] ``` `result` ∈ `SUCCESS|FAILED|PARTIAL`. **POST `/imports/upload`** (multipart, field `file` = CSV; plus `tenantid`) → returns the new log row plus a validation block: ```json { "importid": 922, "result": "PARTIAL", "validation": { "passed": false, "duplicateskus": ["ST-SONA-25K"], "badcolumns": [45, 82], "headerversion": "v2.8" } } ``` Frontend hooks: `useFiestaImportLogs`, `useFiestaImportUpload` (mutation). --- ## [R5] Catalog presets *(optional)* · `GET /products/getcatalogpresets` Inventory "Nilgiris Dairy / Coimbatore Heritage" quick-add packs. **Request:** `tenantid` (✓). **`details`:** ```json [ { "presetid": 3, "name": "Nilgiris Dairy Fresh Pack", "items": [ { "name": "Ooty Butter 500g", "sku": "DY-OOT-BTR", "subcategoryname": "Dairy", "price": 340, "image": "https://…" } ] } ] ``` > Alternative: skip this and reuse master catalog (`/products/getproducts`) filtered by subcategory. --- ## [R6] Merchant settings + branding · `GET /tenants/getsettings` + `PUT /tenants/updatesettings` Replaces the localStorage `DEFAULTS` and the Brand Design Studio local state. **GET request:** `tenantid` (✓). **GET `details`:** ```json { "tenantid": 1087, "contactemail": "ops@ragul.com", "contactphone": "+91…", "minordervalue": 199, "deliverycharge": 29, "prepmins": 20, "deliverywindowmins": 45, "cancelwindowsecs": 120, "autoassignrider": true, "defaulttaxpercent": 5, "codenabled": true, "onlinepaymentenabled": true, "defaultregion": "Coimbatore", "defaultnewuserrole": 4, "ordernotifications": true, "lowstockalerts": true, "dailysummaryemail": false, "syncinterval": 15, "sandboxmode": false, "branding": { "themename": "Kaveri Org", "primarycolor": "#16a34a", "secondarycolor": "#f59e0b", "baglabel": "Freshly Harvested", "ecoverified": true, "stickerpattern": "radial" } } ``` **PUT body:** same object (partial allowed) → returns the updated object. Frontend hooks: `useFiestaSettings`, `useFiestaUpdateSettings` (mutation). --- ## [R7] Forecast insight *(optional)* · `GET /insights/getforecast` Operations "Forecast Efficiency 92% / ₹1.9L savings". Recommend dropping the tiles until a model exists; if kept: **request** `tenantid` (✓), `locationid` (opt). **`details`:** ```json { "forecastefficiencypct": 92, "estsavingsperweek": 190000.00, "horizondays": 7 } ``` --- ## [R8] Stock transfer · `POST /products/stocktransfer` Operations transfer-stock modal. **Body:** ```json { "tenantid": 1087, "productid": 88231, "fromlocationid": 1097, "tolocationid": 1101, "quantity": 100 } ``` **`details`:** updated stock rows for both locations ```json [ { "locationid": 1097, "productid": 88231, "closingstock": 740 }, { "locationid": 1101, "productid": 88231, "closingstock": 360 } ] ``` --- ## [R9] Rider telemetry · `GET /partners/getridertelemetry` Replaces hardcoded rider `rating`, `battery`, `lastPing` and the fake GPS route / "9 MINS" / "1.2 km". **Request:** `applocationid` (✓), `tenantid` (opt), `userid` (opt → single rider). **`details`** (array) ```json [ { "userid": 7781, "name": "Karthikeyan R", "status": "Delivering", "rating": 4.7, "completedtoday": 12, "battery": 84, "lastping": "2026-06-06T14:21:00", "zone": "RS Puram", "lat": 11.0041, "lng": 76.9612, "activedelivery": { "deliveryid": 99213, "etamins": 9, "distancekm": 1.2, "destlat": 11.0102, "destlng": 76.9550 } } ] ``` `status` ∈ `Delivering|Idle|Offline`. `activedelivery` = `null` when the rider is idle. Frontend hook: `useFiestaRiderTelemetry`. --- ## [R10] Intraday dispatch buckets · `GET /deliveries/getdispatchbuckets` Replaces StoreDetail `intervalSlots` (Morning Rush / Midday / Evening Peak computed from %). **Request:** `tenantid` (✓), `locationid` (✓), `date` (✓, default today). **`details`** (array, fixed buckets) ```json [ { "bucket": "06:00-10:00", "label": "Morning Rush", "orders": 64, "revenue": 88400.00, "status": "PEAK" } ] ``` `status` ∈ `PEAK|HIGH|NORMAL|LOW`. Frontend hook: `useFiestaDispatchBuckets`. --- ## [R11] Customer analytics · `GET /customers/getcustomeranalytics` Replaces hardcoded CSAT 5.0 / retention 88.4% / AOV ₹1,580. **Request:** `tenantid` (✓), `locationid` (opt), `customerid` (opt → single-customer rollup). **`details`** (object) ```json { "retentionpct": 88.4, "avgordervalue": 1580.00, "csat": 4.9, "totalcustomers": 1240, "percustomer": { "customerid": 55012, "orderscount": 18, "totalspent": 28450.00, "csat": 5.0, "lastorderdate": "2026-06-04" } } ``` `percustomer` present only when `customerid` is supplied. > Customer order **history** itself already exists: `GET /orders/getorders?customerid=` — wire that, no new API. Frontend hook: `useFiestaCustomerAnalytics`. --- ## [R12] Operational alerts · `GET /alerts/getalerts` Replaces the mock `operationalAlerts` (stock-critical, latency, rebalance…). **Request:** `tenantid` (✓), `locationid` (opt), `status` (`open|all`), `pageno`, `pagesize`. **`details`** (array) ```json [ { "alertid": 5012, "tenantid": 1087, "locationid": 1097, "type": "critical", "title": "Stock Critical: RS Puram", "details": "Dairy inventory below 5%.", "createdat": "2026-06-06T08:24:00", "acknowledged": false } ] ``` `type` ∈ `critical|warning|info`. Frontend hook: `useFiestaAlerts`. --- ## [R13] Scheduled reports *(optional)* · `GET /reports/getschedules` + `POST /reports/createschedule` Replaces 3 hardcoded calendar events. Drop if not on the roadmap. **GET `details`:** ```json [ { "scheduleid": 11, "name": "Monthly Assortment Audit", "cron": "0 0 1 * *", "nextrun": "2026-07-01T00:00:00", "format": "PDF", "recipients": ["ops@ragul.com"] } ] ``` **POST body:** `{ tenantid, name, cron, format, recipients[] }` → returns the created schedule. --- ## Mutation routes already named in the endpoint sheet (publish request/response, then we wire) These are marked `REVIEW_REQUIRED` in `Fiesta_All_Endpoints_With_Tables_And_Params.xlsx`. We need the exact request body + success response for each: | Action | Suggested endpoint | Body (fields we'll send) | |---|---|---| | Create web order | `POST /orders/create` | tenantid, locationid, customerid, items[{productid,qty,price}], paymenttype | | Update order status | `PUT /orders/updatestatus` | orderheaderid, status, financialflag | | Assign rider / dispatch | `POST /deliveries/assign` | orderheaderid, tenantid, locationid, partnerid, userid | | Update pickup / delivered | `PUT /deliveries/updatestatus` | deliveryid, status | | Add multi-product stock | `POST /products/addstock` | tenantid, locationid, items[{productid,qty,cost}] | | Create / update / delete product | `POST/PUT/DELETE /products/...` | product fields | | Onboard tenant / store / location | `POST /tenants/onboard`, `POST /tenants/createlocation` | tenant + location fields | --- ## Frontend status (for reference) - All read endpoints that **already exist** are wired (orders/deliveries/stock/customers/users/ locations/order-line-items/etc.). - Each `[Rxx]` above corresponds to a visible `AwaitingApi` placeholder in the UI, so QA can see exactly which screens are still blocked. - The moment an endpoint here ships with the documented shape, wiring it is one hook + swapping the placeholder — no redesign needed.