Report
This section contains 1 subgroups.
Delivery Report
/report/deliverySummary
GET /report/delivery
Delivery dashboard report.
Storage model
One row per tenant in
public.delivery_report(refreshed nightly).API reads the stored lifetime payload; there is no
rangequery param.If stored
zone_statsare still on the legacy shape, the API rebuilds zone stats live frompublic.deliveries.Header
Authorization: Bearer {{access_token}}All auth failures come from middleware and return
{ "success": false, "message": string, "data": null }with401/403.
Failure aggregation
Delivery failure KPIs and series include the distinct delivery statuses
failed,cancelled, andreturned. Raw delivery rows and exports keep those statuses separate; an RTS-failed hybrid outbound leg remainsfailedand is not rewritten ascancelled.
Zone stats rules
All tenant zones are returned in
zone_stats, even when a zone has no deliveries in the reporting windowZones without deliveries return
0for all totalstotal_inbound_deliveriescounts deliveries wherepickup_zone_id = zone_idtotal_outbound_deliveriescounts deliveries wheredropoff_zone_id = zone_idtotal_deliveriescounts unique deliveries touching the zone by pickup and/or dropoffIf both pickup and dropoff point to the same zone, that delivery is counted once in
total_deliveriestotal_completed_deliveriescounts delivered rows from those unique deliveries
Error responses
401/403(auth/middleware):{ "success": false, "message": string, "data": null }404(report not ready):{ "success": false, "message": "report_not_ready", "data": null }404(unknown module):{ "success": false, "message": string, "data": null }405(method not allowed):{ "success": false, "message": string, "data": null }500:{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/delivery" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "total_deliveries": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "completed": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": [25 0,26 0,27 0,28 0,29 0,30 0,31 032 ]33 },34 "in_progress": {35 "value": 0,36 "trend_percentage": 0,37 "trend_direction": "up",38 "chart_data": []39 },40 "failed": {41 "value": 0,42 "trend_percentage": 0,43 "trend_direction": "up",44 "chart_data": [45 0,46 0,47 0,48 0,49 0,50 0,51 052 ]53 }54 },55 "charts": {56 "status_breakdown": {57 "completed": 0,58 "in_progress": 0,59 "pending": 0,60 "failed": 061 },62 "weekly_performance": {63 "dates": [64 "2025-12-08",65 "2025-12-09",66 "2025-12-10",67 "2025-12-11",68 "2025-12-12",69 "2025-12-13",70 "2025-12-14"71 ],72 "completed": [73 0,74 0,75 0,76 0,77 0,78 0,79 080 ],81 "failed": [82 0,83 0,84 0,85 0,86 0,87 0,88 089 ]90 },91 "metrics_trends": {92 "success_rate": [93 0,94 0,95 0,96 0,97 0,98 0,99 0100 ],101 "avg_delivery_time": [102 0,103 0,104 0,105 0,106 0,107 0,108 0109 ],110 "active_drivers": [111 0,112 0,113 0,114 0,115 0,116 0,117 0118 ]119 }120 },121 "performance": {122 "success_rate": {123 "value": 0,124 "percentage": 0125 },126 "on_time_delivery": {127 "value": 0,128 "percentage": 0129 },130 "customer_satisfaction": {131 "value": 0,132 "percentage": 0133 },134 "first_attempt_success": {135 "value": 0,136 "percentage": 0137 }138 },139 "cod": {140 "collected": 0,141 "remitted": 0,142 "outstanding": 0,143 "wallet_settled": 0144 },145 "top_drivers": [146 {147 "driver_id": "00000000-0000-0000-0000-000000000001",148 "name": "",149 "avatar_url": "",150 "completed_jobs": 0,151 "failed_jobs": 0,152 "avg_time_minutes": 0153 }154 ],155 "zone_stats": [156 {157 "zone_id": "11111111-1111-1111-1111-111111111111",158 "zone_code": "ZN-001",159 "zone_name": "Central Zone",160 "total_deliveries": 0,161 "total_inbound_deliveries": 0,162 "total_outbound_deliveries": 0,163 "total_completed_deliveries": 0164 }165 ],166 "recent_activity": [167 {168 "id": "00000000-0000-0000-0000-000000000100",169 "order_ref": "",170 "type": "pending",171 "message": "",172 "timestamp": "2025-12-14T00:00:00.000Z"173 }174 ]175 }176}Storefront Report
/report/storefrontSummary
GET /report/storefront
Storefront dashboard report.
Storage model
One row per tenant in
public.storefront_report(refreshed nightly).API reads the stored lifetime payload; there is no
rangequery param.Header
Authorization: Bearer {{access_token}}
Same envelope
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/storefront" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "weekly_sales": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "new_customers": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": []25 },26 "purchase_orders": {27 "value": 0,28 "trend_percentage": 0,29 "trend_direction": "up",30 "chart_data": []31 },32 "messages": {33 "value": 0,34 "trend_percentage": 0,35 "trend_direction": "up",36 "chart_data": []37 }38 },39 "summary": {40 "product_sold": {41 "value": 0,42 "trend_percentage": 043 },44 "total_balance": {45 "value": 0,46 "trend_percentage": 047 },48 "sales_profit": {49 "value": 0,50 "trend_percentage": 051 }52 },53 "charts": {54 "sale_by_gender": [55 {56 "label": "Men",57 "value": 058 },59 {60 "label": "Women",61 "value": 062 },63 {64 "label": "Kids",65 "value": 066 }67 ],68 "yearly_sales": {69 "categories": [70 "Jan",71 "Feb",72 "Mar",73 "Apr",74 "May",75 "Jun",76 "Jul",77 "Aug",78 "Sep",79 "Oct",80 "Nov",81 "Dec"82 ],83 "series": [84 {85 "name": "2023",86 "data": [87 0,88 0,89 0,90 0,91 0,92 0,93 0,94 0,95 0,96 0,97 0,98 099 ]100 },101 {102 "name": "2024",103 "data": [104 0,105 0,106 0,107 0,108 0,109 0,110 0,111 0,112 0,113 0,114 0,115 0116 ]117 }118 ]119 }120 },121 "finances": {122 "sales_overview": {123 "total_profit": {124 "value": 0,125 "percentage": 0126 },127 "total_income": {128 "value": 0,129 "percentage": 0130 },131 "total_expenses": {132 "value": 0,133 "percentage": 0134 }135 },136 "current_balance": {137 "total": 0,138 "breakdown": {139 "order_total": 0,140 "earning": 0,141 "refunded": 0142 }143 }144 },145 "best_sellers": [146 {147 "seller_id": "00000000-0000-0000-0000-000000000001",148 "name": "",149 "avatar_url": "",150 "product_category": "",151 "country_code": "",152 "total_sales": 0,153 "rank": 1154 }155 ],156 "latest_products": [157 {158 "id": "00000000-0000-0000-0000-000000000010",159 "name": "",160 "image_url": "",161 "price": 0,162 "original_price": 0,163 "is_active": true164 }165 ]166 }167}Warehouse Report
/report/warehouseSummary
GET /report/warehouse
Warehouse dashboard report.
Storage model
One row per tenant in
public.warehouse_report(refreshed nightly).API reads the stored lifetime payload; there is no
rangequery param.Header
Authorization: Bearer {{access_token}}
Same envelope
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/warehouse" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "items_received": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "items_dispatched": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": [25 0,26 0,27 0,28 0,29 0,30 0,31 032 ]33 },34 "total_stock": {35 "value": 0,36 "trend_percentage": 0,37 "trend_direction": "up",38 "chart_data": []39 },40 "picking_orders": {41 "value": 0,42 "trend_percentage": 0,43 "trend_direction": "up",44 "chart_data": []45 }46 },47 "charts": {48 "weekly_receiving": [49 0,50 0,51 0,52 0,53 0,54 0,55 056 ],57 "weekly_dispatching": [58 0,59 0,60 0,61 0,62 0,63 0,64 065 ],66 "completed_audits": [67 0,68 0,69 0,70 0,71 0,72 0,73 074 ],75 "capacity_utilization": {76 "used": 0,77 "available": 0,78 "percentage": 079 },80 "inventory_movement": {81 "dates": [82 "2025-12-08",83 "2025-12-09",84 "2025-12-10",85 "2025-12-11",86 "2025-12-12",87 "2025-12-13",88 "2025-12-14"89 ],90 "received": [91 0,92 0,93 0,94 0,95 0,96 0,97 098 ],99 "dispatched": [100 0,101 0,102 0,103 0,104 0,105 0,106 0107 ]108 }109 },110 "performance": {111 "items_received": {112 "current": 0,113 "target": 0,114 "percentage": 0115 },116 "items_dispatched": {117 "current": 0,118 "target": 0,119 "percentage": 0120 },121 "picking_orders": {122 "current": 0,123 "target": 0,124 "percentage": 0125 },126 "audits_completed": {127 "current": 0,128 "target": 0,129 "percentage": 0130 }131 },132 "summary": {133 "total_stock_items": 0,134 "total_stock_value": 0,135 "capacity_used_percentage": 0136 },137 "stock_levels": [138 {139 "item_name": "",140 "sku": "",141 "quantity": 0,142 "capacity_max": 0,143 "status": "In Stock",144 "status_color": "green"145 }146 ],147 "recent_activity": [148 {149 "id": "00000000-0000-0000-0000-000000000001",150 "type": "received",151 "message": "",152 "timestamp": "2025-12-14T00:00:00.000Z",153 "reference_id": ""154 }155 ]156 }157}Restaurant Report
/report/restaurantSummary
GET /report/restaurant
Restaurant dashboard report.
Storage model
One row per tenant in
public.restaurant_report(refreshed nightly).API reads the stored lifetime payload; there is no
rangequery param.Header
Authorization: Bearer {{access_token}}
Same envelope
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/restaurant" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "todays_orders": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "todays_revenue": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": [25 0,26 0,27 0,28 0,29 0,30 0,31 032 ]33 },34 "active_tables": {35 "value": 0,36 "trend_percentage": 0,37 "trend_direction": "up",38 "chart_data": []39 },40 "avg_prep_time": {41 "value": 0,42 "trend_percentage": 0,43 "trend_direction": "up",44 "chart_data": []45 }46 },47 "charts": {48 "weekly_orders": [49 0,50 0,51 0,52 0,53 0,54 0,55 056 ],57 "weekly_revenue": [58 0,59 0,60 0,61 0,62 0,63 0,64 065 ],66 "avg_order_value": [67 0,68 0,69 0,70 0,71 0,72 0,73 074 ],75 "order_status_breakdown": {76 "completed": 0,77 "in_progress": 0,78 "pending": 0,79 "cancelled": 080 },81 "revenue_by_type": {82 "dates": [83 "2025-12-08",84 "2025-12-09",85 "2025-12-10",86 "2025-12-11",87 "2025-12-12",88 "2025-12-13",89 "2025-12-14"90 ],91 "dine_in": [92 0,93 0,94 0,95 0,96 0,97 0,98 099 ],100 "takeaway": [101 0,102 0,103 0,104 0,105 0,106 0,107 0108 ]109 }110 },111 "performance": {112 "total_revenue": {113 "current": 0,114 "target": 0,115 "percentage": 0116 },117 "total_orders": {118 "current": 0,119 "target": 0,120 "percentage": 0121 },122 "total_expenses": {123 "current": 0,124 "target": 0,125 "percentage": 0126 },127 "todays_summary": {128 "revenue": 0,129 "orders": 0,130 "aov": 0131 }132 },133 "popular_items": [134 {135 "item_id": "00000000-0000-0000-0000-000000000001",136 "name": "",137 "image_url": "",138 "category": "",139 "orders_count": 0,140 "revenue": 0,141 "status": "Available",142 "status_color": "green"143 }144 ],145 "recent_orders": [146 {147 "id": "00000000-0000-0000-0000-000000000010",148 "order_ref": "",149 "description": "",150 "status": "Pending",151 "timestamp": "2025-12-14T00:00:00.000Z"152 }153 ]154 }155}Express Shipping Report
/report/expressSummary
GET /report/express
Express (shipping) dashboard report.
Storage model
One row per tenant in
public.express_report(refreshed nightly).API reads the stored lifetime payload; there is no
rangequery param.Header
Authorization: Bearer {{access_token}}
Same envelope
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/express" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "total_packages": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "delivered": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": []25 },26 "in_transit": {27 "value": 0,28 "trend_percentage": 0,29 "trend_direction": "up",30 "chart_data": []31 },32 "pending_claim": {33 "value": 0,34 "trend_percentage": 0,35 "trend_direction": "up",36 "chart_data": []37 }38 },39 "charts": {40 "weekly_volume": [41 0,42 0,43 0,44 0,45 0,46 0,47 048 ],49 "total_weight_kg": [50 0,51 0,52 0,53 0,54 0,55 0,56 057 ],58 "avg_delivery_time": [59 0,60 0,61 0,62 0,63 0,64 0,65 066 ],67 "status_distribution": {68 "delivered": 0,69 "in_transit": 0,70 "processing": 0,71 "received": 0,72 "pending_claim": 073 },74 "shipping_volume_bar": {75 "dates": [76 "2025-12-08",77 "2025-12-09",78 "2025-12-10",79 "2025-12-11",80 "2025-12-12",81 "2025-12-13",82 "2025-12-14"83 ],84 "received": [85 0,86 0,87 0,88 0,89 0,90 0,91 092 ],93 "delivered": [94 0,95 0,96 0,97 0,98 0,99 0,100 0101 ]102 }103 },104 "revenue": {105 "domestic_fees": 0,106 "international_fees": 0,107 "delivery_fees": 0,108 "total_revenue": 0109 },110 "metrics": {111 "delivered": {112 "value": 0,113 "percentage": 0114 },115 "in_transit": {116 "value": 0,117 "percentage": 0118 },119 "processing": {120 "value": 0,121 "percentage": 0122 },123 "pending_claim": {124 "value": 0,125 "percentage": 0126 }127 },128 "top_stores": [129 {130 "store_name": "",131 "package_count": 0132 }133 ],134 "recent_packages": [135 {136 "tracking_number": "",137 "store_name": "",138 "customer_name": "",139 "weight_kg": 0,140 "status": "Received",141 "status_color": "orange",142 "payment_status": "Pending",143 "created_at": "2025-12-14T00:00:00.000Z"144 }145 ],146 "recent_activity": [147 {148 "id": "00000000-0000-0000-0000-000000000001",149 "message": "",150 "type": "received",151 "timestamp": "2025-12-14T00:00:00.000Z"152 }153 ]154 }155}Tenant App Report (Common)
/report/appSummary
GET /report/app
Tenant application (common) report that returns the exact dashboard widget payload the portal uses.
Storage model
One row per tenant in
public.tenant_app_report(refreshed nightly).Header
Authorization: Bearer {{access_token}}
Same envelope
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/app" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "delivery_overview": {6 "total_deliveries_period": 0,7 "completed_deliveries_period": 0,8 "pending_deliveries_current": 0,9 "in_progress_deliveries_current": 0,10 "failed_deliveries_period": 0,11 "delivery_success_rate_period": 0,12 "avg_delivery_time_minutes_period": 0,13 "avg_pickup_to_delivery_time_minutes_period": 014 },15 "cod_summary": {16 "total_cod_collected_period": 0,17 "total_cod_remitted_period": 0,18 "total_cod_outstanding_current": 0,19 "total_cod_settled_by_wallet_period": 020 },21 "warehouse_overview": {22 "total_items_received_period": 0,23 "total_items_dispatched_period": 0,24 "current_total_stock_items": 0,25 "current_total_stock_value": 0,26 "overall_capacity_utilization_percent_current": 0,27 "total_picking_orders_completed_period": 0,28 "total_batches_dispatched_period": 029 },30 "warehouse_activity_by_warehouse": {31 "data": [32 {33 "warehouse_id": "00000000-0000-0000-0000-000000000001",34 "warehouse_name": "",35 "items_received_period": 0,36 "items_dispatched_period": 0,37 "current_stock_items": 0,38 "capacity_utilization_percent": 039 }40 ],41 "columns": [42 {43 "field": "warehouse_name",44 "label": "Warehouse",45 "description": "Warehouse name",46 "type": "string"47 },48 {49 "field": "items_received_period",50 "label": "Received",51 "description": "Items received in period",52 "type": "number"53 },54 {55 "field": "items_dispatched_period",56 "label": "Dispatched",57 "description": "Items dispatched in period",58 "type": "number"59 },60 {61 "field": "current_stock_items",62 "label": "Stock",63 "description": "Current stock items",64 "type": "number"65 },66 {67 "field": "capacity_utilization_percent",68 "label": "Capacity %",69 "description": "Capacity utilization percent",70 "type": "number"71 }72 ]73 },74 "warehouse_stock_by_category": {75 "data": [76 {77 "category_id": "00000000-0000-0000-0000-000000000010",78 "category_name": {79 "en": ""80 },81 "stock_items": 082 }83 ],84 "columns": [85 {86 "field": "category_name",87 "label": "Category",88 "description": "Inventory category",89 "type": "jsonb"90 },91 {92 "field": "stock_items",93 "label": "Stock Items",94 "description": "Stock items in category",95 "type": "number"96 }97 ]98 }99 }100}Trigger Daily Aggregation (Cron)
/reportSummary
POST /report
Refreshes stored lifetime-to-date reports for each tenant across delivery, storefront, warehouse, restaurant, express, and tenant-app modules.
Internal backend/cron only. Send apikey: {{supabase_secret_key}} with the default managed Supabase secret key (SUPABASE_SECRET_KEYS.default). Never put this value in a frontend or mobile application. Missing, invalid, publishable, legacy anon, and legacy service-role bearer credentials return HTTP 401 before work is dispatched. Authorization: Bearer ... alone is not accepted. Frontend handoff: none; application clients must not call this internal endpoint. The unauthorized message is localized using the request language.
Only literal recalculate_all: true expands the driver-performance recalculation and top-driver range to start at 2020-01-01. Omitted/false/unparseable bodies use the current UTC month for that range. Lifetime delivery totals, recent chart windows, and other module reports still refresh. date is not read by this handler.
HTTP 200 may report success: false when one or more tenants fail; inspect tenants_failed and failed[] in addition to HTTP status.
Error responses
HTTP 401:
{ "success": false, "message": "Unauthorized" }(localized).Scheduler failures use the same response envelope:
{ "success": false, "message": string, "data": null }
Headers
| Parameter | Type | Description |
|---|---|---|
Content-Type | string | Example: |
apikey | string | Default managed Supabase secret key; backend only. Example: |
Body parameters
| Parameter | Type | Description |
|---|---|---|
recalculate_all | boolean | — |
1curl --globoff --request POST "https://staging-api.ondi.io/functions/v1/report" \2 --header "Content-Type: application/json" \3 --header "apikey: ${SUPABASE_SECRET_KEY}" \4 --data-raw '{5 "recalculate_all": false6}'Internal backend endpoint. Run from a trusted server; keep backend secret keys out of the browser.
Response examples
1{2 "success": true,3 "message": "Lifetime report refresh completed",4 "data": {5 "duration_ms": "12.34",6 "tenants_ok": 0,7 "tenants_failed": 0,8 "failed": []9 }10}Legacy - Delivery Overview
/report/tenant/delivery/overviewSummary
GET /report/tenant/delivery/overview
Legacy route. Router maps any /report/tenant/delivery/* to module delivery.
Effective route
GET /report/deliveryHeader
Authorization: Bearer {{access_token}}
Same as Delivery Report but wrapped envelope:
{ success: true, message: "", data: DeliveryDashboardResponse }
Same envelope
{ success: false, message: string, data: null }
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/tenant/delivery/overview" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": {5 "kpis": {6 "total_deliveries": {7 "value": 0,8 "trend_percentage": 0,9 "trend_direction": "up",10 "chart_data": [11 0,12 0,13 0,14 0,15 0,16 0,17 018 ]19 },20 "completed": {21 "value": 0,22 "trend_percentage": 0,23 "trend_direction": "up",24 "chart_data": [25 0,26 0,27 0,28 0,29 0,30 0,31 032 ]33 },34 "in_progress": {35 "value": 0,36 "trend_percentage": 0,37 "trend_direction": "up",38 "chart_data": []39 },40 "failed": {41 "value": 0,42 "trend_percentage": 0,43 "trend_direction": "up",44 "chart_data": [45 0,46 0,47 0,48 0,49 0,50 0,51 052 ]53 }54 },55 "charts": {56 "status_breakdown": {57 "completed": 0,58 "in_progress": 0,59 "pending": 0,60 "failed": 061 },62 "weekly_performance": {63 "dates": [64 "2025-12-08",65 "2025-12-09",66 "2025-12-10",67 "2025-12-11",68 "2025-12-12",69 "2025-12-13",70 "2025-12-14"71 ],72 "completed": [73 0,74 0,75 0,76 0,77 0,78 0,79 080 ],81 "failed": [82 0,83 0,84 0,85 0,86 0,87 0,88 089 ]90 },91 "metrics_trends": {92 "success_rate": [93 0,94 0,95 0,96 0,97 0,98 0,99 0100 ],101 "avg_delivery_time": [102 0,103 0,104 0,105 0,106 0,107 0,108 0109 ],110 "active_drivers": [111 0,112 0,113 0,114 0,115 0,116 0,117 0118 ]119 }120 },121 "performance": {122 "success_rate": {123 "value": 0,124 "percentage": 0125 },126 "on_time_delivery": {127 "value": 0,128 "percentage": 0129 },130 "customer_satisfaction": {131 "value": 0,132 "percentage": 0133 },134 "first_attempt_success": {135 "value": 0,136 "percentage": 0137 }138 },139 "cod": {140 "collected": 0,141 "remitted": 0,142 "outstanding": 0,143 "wallet_settled": 0144 },145 "top_drivers": [146 {147 "driver_id": "00000000-0000-0000-0000-000000000001",148 "name": "",149 "avatar_url": "",150 "completed_jobs": 0,151 "failed_jobs": 0,152 "avg_time_minutes": 0153 }154 ],155 "zone_stats": [156 {157 "zone_id": "11111111-1111-1111-1111-111111111111",158 "zone_code": "ZN-001",159 "zone_name": "Central Zone",160 "total_deliveries": 0,161 "total_inbound_deliveries": 0,162 "total_outbound_deliveries": 0,163 "total_completed_deliveries": 0164 }165 ],166 "recent_activity": [167 {168 "id": "00000000-0000-0000-0000-000000000100",169 "order_ref": "",170 "type": "pending",171 "message": "",172 "timestamp": "2025-12-14T00:00:00.000Z"173 }174 ]175 }176}Driver Performance
/report/tenant/delivery/driver-performanceSummary
GET /report/tenant/delivery/driver-performance
Returns driver performance metrics computed by the nightly report scheduler. Data is read from the driver_performance_metrics table (populated during cron).
Header
Authorization: Bearer {{access_token}}
Response fields
| Field | Type | Description |
|---|---|---|
driver_id | UUID | Driver identifier |
driver_name | string | Driver's full name |
total_deliveries | integer | Total terminal-status assignments (completed + failed) |
successful_deliveries | integer | Assignments with status completed/delivered/closed |
failed_deliveries | integer | Assignments with status failed/cancelled/rejected/returned |
on_time_deliveries | integer | Completed before scheduled_delivery_time |
late_deliveries | integer | Completed after scheduled_delivery_time |
success_rate | decimal | (successful / total) × 100 |
on_time_rate | decimal | (on_time / (on_time + late)) × 100 |
average_delivery_time_minutes | integer | Mean minutes from pickup to drop-off |
total_distance_km | decimal | Sum of distance_traveled across assignments |
km_per_delivery | decimal | total_distance / successful_deliveries |
total_delivery_value | decimal | Sum of (cod_amount + delivery_fee) for completed |
KPI Cards (aggregate across all drivers)
Total Deliveries — sum of
total_deliveriesOverall Success Rate — sum(successful) / sum(total) × 100
Overall On-Time Rate — sum(
on_time) / sum(on_time+ late) × 100Avg Delivery Time — weighted average of
average_delivery_time_minutesTotal Revenue Handled — sum of
total_delivery_valueActive Drivers — count of drivers with
total_deliveries> 0
Column Filters (planned)
All numeric columns support {min, max} range filtering:
total_deliveries,success_rate,on_time_rate,average_delivery_time,km_per_delivery,total_delivery_value
Error responses
400:{ "success": false, "message": "tenantId missing in request context", "data": null }500:{ "success": false, "message": "query_failed", "data": null }
Query parameters
| Parameter | Type | Description |
|---|---|---|
tenant_id | string | Example: |
language | string | Example: |
Headers
| Parameter | Type | Description |
|---|---|---|
Authorization | string | Example: |
1curl --globoff --request GET "https://staging-api.ondi.io/functions/v1/report/tenant/delivery/driver-performance?tenant_id=${TENANT_ID}&language=en" \2 --header "Authorization: Bearer ${ONDI_ACCESS_TOKEN}"Response examples
1{2 "success": true,3 "message": "",4 "data": [5 {6 "driver_id": "a1b2c3d4-0000-0000-0000-000000000001",7 "driver_name": "Ahmed Ali",8 "total_deliveries": 120,9 "successful_deliveries": 108,10 "failed_deliveries": 12,11 "on_time_deliveries": 95,12 "late_deliveries": 13,13 "success_rate": 90,14 "on_time_rate": 87.96,15 "average_delivery_time_minutes": 28,16 "total_distance_km": 840.5,17 "km_per_delivery": 7.78,18 "total_delivery_value": 4500019 },20 {21 "driver_id": "a1b2c3d4-0000-0000-0000-000000000002",22 "driver_name": "Mohammed Saeed",23 "total_deliveries": 95,24 "successful_deliveries": 90,25 "failed_deliveries": 5,26 "on_time_deliveries": 82,27 "late_deliveries": 8,28 "success_rate": 94.74,29 "on_time_rate": 91.11,30 "average_delivery_time_minutes": 24,31 "total_distance_km": 620.3,32 "km_per_delivery": 6.89,33 "total_delivery_value": 3850034 }35 ]36}