Back-office order reporting: a detailed per-order report, a cancelled/expired report,
and a per-day operational consolidation. Each has a CSV export. Paths are relative to
the /api/v1 prefix; these are back-office endpoints that require an admin token.
Requires an admin bearer token (see Admin auth). Admin only. Results are scoped to the admin's assigned cities.
See Common errors and the order money breakdown.
All reports are read-only. All money is reported in USD. A date range is required to
span at most 30 days; a wider range returns 422. When omitted, the range
defaults to the last 30 days. List endpoints are page-based; see
Pagination → page-based. Every .../export
endpoint accepts ?format=csv|xlsx (default csv); xlsx returns
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
Every report accepts sort (a column key from its allowed list below) and direction
(asc|desc, default desc). An unknown sort key or direction value returns 422.
The list endpoints sort the full dataset before paginating, and .../export uses the same
sort as its list endpoint.
| Method | URI | Access | Description |
|---|---|---|---|
GET |
/admin/reports/orders |
Admin | Detailed orders, one row per order |
GET |
/admin/reports/orders/export |
Admin | CSV export of the detailed report |
GET |
/admin/reports/orders/cancellations |
Admin | Cancelled & expired orders |
GET |
/admin/reports/orders/cancellations/export |
Admin | CSV export of the cancellations report |
GET |
/admin/reports/orders/operational |
Admin | Operational consolidation, one row per day |
GET |
/admin/reports/orders/operational/export |
Admin | CSV export of the operational report |
Detailed report with one row per order, in any state.
Query
| Field | Type | Required | Rules |
|---|---|---|---|
date_from |
date | no | start of the range; defaults to 29 days before date_to |
date_to |
date | no | end of the range; >= date_from; span ≤ 30 days |
city_id |
integer | no | filter by the order's city |
status |
string | no | order status value (BROADCASTING…EXPIRED) |
driver_id |
integer | no | |
client_id |
integer | no | |
water_type |
string | no | POTABLE or INDUSTRIAL |
payment_method |
string | no | payment method value |
payment_status |
string | no | confirmed, pending, or failed |
origin |
string | no | app or remate |
has_counter_offer |
boolean | no | |
has_incident |
boolean | no | |
rating_min |
integer | no | 1–5 |
rating_max |
integer | no | 1–5 |
sort |
string | no | one of the sortable keys below; default newest first |
direction |
string | no | asc or desc (default desc) |
limit |
integer | no | 1–100, default 25 |
page |
integer | no | ≥ 1, default 1 |
Sortable sort keys: id, created_at, status, water_type, city_name,
client_name, driver_name, liters_requested, liters_delivered, liters_diff,
base_price_usd, final_price_usd, commission_usd, driver_net_usd,
acceptance_minutes, delivery_minutes, rating, incidents.
Response 200
{
"items": [
{
"id": 42,
"created_at": "2026-07-18T12:40:00+00:00",
"status": "DELIVERED",
"status_label": "Entregado",
"city_id": 3,
"city_name": "Caracas",
"client_id": 1,
"client_name": "Ana Martínez",
"driver_id": 7,
"driver_name": "Luis Pérez",
"plate": "ABC123",
"address": "Av. X, Caracas",
"water_type": "POTABLE",
"liters_requested": 1000,
"liters_delivered": 1000,
"liters_diff": 0,
"liters_diff_flagged": false,
"base_price_usd": 10.0,
"final_price_usd": 10.0,
"payment_method": "CASH_USD",
"payment_method_label": "Cash USD",
"payment_status": "No aplica",
"commission_usd": 1.8,
"solidary_fund_usd": 0.18,
"driver_net_usd": 8.12,
"origin": "app",
"has_counter_offer": false,
"acceptance_minutes": 3,
"delivery_minutes": 25,
"rating": 5,
"incidents": 0
}
],
"meta": { "total": 137, "per_page": 25, "current_page": 1, "last_page": 6 },
"totals": {
"pedidos": 137,
"litros_solicitados": 137000,
"litros_entregados": 120000,
"monto_bruto_usd": 1370.0,
"comision_usd": 246.6,
"neto_conductores_usd": 1112.4
}
}
Errors
| Status | Body | When |
|---|---|---|
422 |
{ "error": "ValidationError", "details": { "fieldErrors": { "date_to": ["…"] } } } |
Range wider than 30 days, or invalid filter |
Streams the filtered detailed report as a CSV download (text/csv); there is no JSON
body on success. Accepts the same filters as the detailed report (no pagination).
Response 200 — a text/csv stream (reporte_ordenes_<timestamp>.csv) with the
columns Fecha creación, Pedido, Estado, Ciudad, Cliente, Conductor, Placa, Dirección, Tipo de agua, Litros solicitados, Litros entregados, Dif. litros, Precio base (USD), Precio final (USD), Método de pago, Estado de pago, Comisión (USD), Fondo solidario (USD), Neto conductor (USD), Origen, Contraoferta, Tiempo aceptación (min), Tiempo entrega (min), Calificación, Incidencias.
Errors
| Status | Body | When |
|---|---|---|
422 |
{ "error": "ValidationError", … } |
Range wider than 30 days, or invalid filter |
Cancelled and expired orders only. The date range applies to the cancellation/expiration moment.
Query
| Field | Type | Required | Rules |
|---|---|---|---|
date_from |
date | no | start of the range; span ≤ 30 days |
date_to |
date | no | end of the range; >= date_from |
city_id |
integer | no | filter by the order's city |
cancelled_role |
string | no | cliente, conductor, admin, or sistema |
status_at_cancel |
string | no | BROADCASTING, WAITING_FOR_PAYMENT, CONFIRMED, or IN_PROGRESS |
driver_id |
integer | no | |
client_id |
integer | no | |
with_refund |
boolean | no | |
sort |
string | no | one of the sortable keys below; default newest first |
direction |
string | no | asc or desc (default desc) |
limit |
integer | no | 1–100, default 25 |
page |
integer | no | ≥ 1, default 1 |
Sortable sort keys: id, date, final_status, client_name, driver_name,
liters, unrealized_usd, minutes_to_cancel.
Response 200
{
"items": [
{
"id": 51,
"date": "2026-07-18T10:05:00+00:00",
"final_status": "CANCELLED",
"cancelled_by": "cliente",
"status_at_cancel": "BROADCASTING",
"reason": "Ya no lo necesito",
"client_name": "Ana Martínez",
"driver_name": null,
"liters": 1000,
"unrealized_usd": 10.0,
"minutes_to_cancel": 4,
"charged_before": false,
"refunded": false,
"recovered": true
}
],
"meta": { "total": 12, "per_page": 25, "current_page": 1, "last_page": 1 },
"totals": {
"cancelled_by_client": 5,
"cancelled_by_driver": 2,
"cancelled_by_admin": 1,
"expired": 4,
"unrealized_usd": 120.0,
"recovery_rate": 41.7
}
}
Errors
| Status | Body | When |
|---|---|---|
422 |
{ "error": "ValidationError", … } |
Range wider than 30 days, or invalid filter |
Streams the filtered cancellations report as a CSV download (text/csv); no JSON body on
success. Same filters, no pagination.
Response 200 — a text/csv stream (reporte_cancelaciones_<timestamp>.csv) with the
columns Fecha, Pedido, Estado final, Canceló, Estado al cancelar, Motivo, Ciudad, Cliente, Conductor, Litros, Monto no concretado (USD), Tiempo hasta cancelar (min), Cobro previo, Reembolso, Recuperado.
Operational consolidation with one row per calendar day (by creation date).
Query
| Field | Type | Required | Rules |
|---|---|---|---|
date_from |
date | no | start of the range; span ≤ 30 days |
date_to |
date | no | end of the range; >= date_from |
city_id |
integer | no | filter by the order's city |
client_id |
integer | no | limit to one client |
driver_id |
integer | no | limit to one driver |
water_type |
string | no | POTABLE or INDUSTRIAL |
sort |
string | no | one of the sortable keys below; default chronological |
direction |
string | no | asc or desc (default desc) |
Sortable sort keys: date, published, accepted, delivered, cancelled,
expired, conversion_pct, liters_requested, liters_delivered, avg_ticket_usd,
avg_acceptance_minutes, avg_delivery_minutes, active_drivers, gross_income_usd,
commission_usd. Without sort, rows stay in chronological order. sort reorders only
the items; totals and comparison are unaffected.
Response 200
{
"items": [
{
"date": "2026-07-18",
"published": 10,
"accepted": 8,
"delivered": 7,
"cancelled": 2,
"expired": 1,
"conversion_pct": 70,
"liters_requested": 10000,
"liters_delivered": 7000,
"avg_ticket_usd": 10.0,
"avg_acceptance_minutes": 3.2,
"avg_delivery_minutes": 24.8,
"active_drivers": 5,
"gross_income_usd": 70.0,
"commission_usd": 12.6
}
],
"totals": {
"published": 10,
"accepted": 8,
"delivered": 7,
"cancelled": 2,
"expired": 1,
"conversion_pct": 70,
"liters_requested": 10000,
"liters_delivered": 7000,
"avg_ticket_usd": 10.0,
"avg_acceptance_minutes": 3.2,
"avg_delivery_minutes": 24.8,
"active_drivers": 5,
"gross_income_usd": 70.0,
"commission_usd": 12.6
},
"comparison": {
"previous_period": { "from": "2026-06-18T00:00:00+00:00", "to": "2026-07-17T23:59:59+00:00" },
"previous": { "published": 8, "delivered": 6, "gross_income_usd": 60.0, "commission_usd": 10.8, "conversion_pct": 75 },
"variation_pct": { "published": 25.0, "delivered": 16.7, "cancelled": null, "expired": null, "gross_income_usd": 16.7, "commission_usd": 16.7, "conversion_pct": -6.7 }
}
}
variation_pct is null when the previous-period value is 0.
Errors
| Status | Body | When |
|---|---|---|
422 |
{ "error": "ValidationError", … } |
Range wider than 30 days, or invalid filter |
Streams the filtered operational report as a CSV download (text/csv); no JSON body on
success. Same filters.
Response 200 — a text/csv stream (reporte_operativo_<timestamp>.csv) with the
columns Fecha, Publicados, Aceptados, Entregados, Cancelados, Expirados, Conversión (%), Litros solicitados, Litros entregados, Ticket promedio (USD), T. medio aceptación (min), T. medio entrega (min), Conductores activos, Ingreso bruto (USD), Comisión (USD).