Files
daily_merchant_web/docs/BACKEND_API_REQUIREMENTS.md

13 KiB
Raw Permalink Blame History

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/<group>/<action>. 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
    { "code": 200, "status": true, "message": "OK", "details": <payload> }
    
    details is the documented payload (array or object). On failure return { "code": 4xx, "status": false, "message": "<reason>" }.
  • 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)

{
  "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)

[
  { "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)

[
  { "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 } ] }
]

trendup|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

[
  { "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" }
]

resultSUCCESS|FAILED|PARTIAL.

POST /imports/upload (multipart, field file = CSV; plus tenantid) → returns the new log row plus a validation block:

{ "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:

[ { "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:

{
  "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:

{ "forecastefficiencypct": 92, "estsavingsperweek": 190000.00, "horizondays": 7 }

[R8] Stock transfer · POST /products/stocktransfer

Operations transfer-stock modal. Body:

{ "tenantid": 1087, "productid": 88231,
  "fromlocationid": 1097, "tolocationid": 1101, "quantity": 100 }

details: updated stock rows for both locations

[ { "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)

[
  { "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 } }
]

statusDelivering|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)

[ { "bucket": "06:00-10:00", "label": "Morning Rush",
    "orders": 64, "revenue": 88400.00, "status": "PEAK" } ]

statusPEAK|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)

{
  "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)

[ { "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 } ]

typecritical|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:

[ { "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.