Admin driver reports

Back-office cisternero (driver) reporting: a detailed per-driver report, a per-period performance report, and a documentation/KYC report. 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.

All reports are read-only; money is reported in USD. Some columns are always null: online_hours, notified, acceptance_rate, unanswered, avg_response_minutes. The detailed and documentation lists are page-based; see Pagination → page-based. Every .../export endpoint accepts ?format=csv|xlsx (default csv); xlsx returns application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.

The detailed and documentation reports accept sort (a column key from their allowed list below) and direction (asc|desc, default desc). An unknown sort key or direction value returns 422. The detailed list sorts the full dataset before paginating; .../export uses the same sort as its list endpoint. The performance report is not sortable — its rows stay ordered by period, then by rank.

Endpoints

Method URI Access Description
GET /admin/reports/drivers Admin Detailed drivers, one row per driver
GET /admin/reports/drivers/export Admin CSV export of the detailed report
GET /admin/reports/drivers/documents Admin Documentation & KYC, one row per driver × document
GET /admin/reports/drivers/documents/export Admin CSV export of the documentation report
GET /admin/reports/drivers/performance Admin Performance, one row per driver × period
GET /admin/reports/drivers/performance/export Admin CSV export of the performance report

GET /admin/reports/drivers

Detailed report with one row per driver, in any KYC state.

Query

Field Type Required Rules
kyc_state string no PENDING_KYC, PENDING_REVIEW, APPROVED, REJECTED
availability string no en_linea, fuera_de_linea, or bloqueado
rating_min number no 0–5
rating_max number no 0–5
with_cash_debt boolean no only drivers with cash_debt > 0
min_balance number no USD, ≥ 0
capacity_min integer no vehicle liters
capacity_max integer no vehicle liters
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: name, registered_at, kyc_state, rating, ratings_count, capacity, balance_usd, cash_debt_usd, last_activity, deliveries, liters_delivered, gross_earnings_usd, commission_paid_usd, own_cancellations.

Response 200

{
  "items": [
    {
      "driver_id": 7,
      "name": "Luis Pérez",
      "id_number": "V12345678",
      "phone": "+58412...",
      "registered_at": "2026-02-01T10:00:00+00:00",
      "kyc_state": "APPROVED",
      "availability": "en_linea",
      "block_reason": null,
      "plate": "XYZ999",
      "capacity": 8000,
      "deliveries": 42,
      "unanswered": null,
      "acceptance_rate": null,
      "own_cancellations": 1,
      "liters_delivered": 42000,
      "gross_earnings_usd": 341.04,
      "commission_paid_usd": 75.6,
      "solidary_usd": 3.4,
      "balance_usd": 50.0,
      "cash_debt_usd": 3.0,
      "rating": 4.7,
      "ratings_count": 30,
      "incidents": 2,
      "last_activity": "2026-07-20T08:00:00+00:00"
    }
  ],
  "meta": { "total": 60, "per_page": 25, "current_page": 1, "last_page": 3 },
  "totals": {
    "conductores": 60,
    "aprobados": 48,
    "bloqueados": 3,
    "litros_entregados": 1200000,
    "ganancia_bruta_usd": 9744.0,
    "comision_usd": 2160.0,
    "deuda_cash_total_usd": 120.0
  }
}

availability is bloqueado when the driver is SUSPENDED or BANNED. gross_earnings_usd is the amount credited to the driver; commission_paid_usd is what Agüita retained.

Errors

Status Body When
422 { "error": "ValidationError", … } Invalid filter value

GET /admin/reports/drivers/export

Streams the filtered detailed report as CSV (text/csv); no JSON body on success. Same filters (no pagination).

Response 200 — a text/csv stream (reporte_cisterneros_<timestamp>.csv) with the columns Conductor, Cédula, Teléfono, Fecha registro, Estado KYC, Disponibilidad, Motivo bloqueo, Placa, Capacidad, Entregas, No respondidos, Tasa aceptación (%), Cancelaciones, Litros entregados, Ganancia bruta (USD), Comisión pagada (USD), Aporte solidario (USD), Saldo actual (USD), Deuda cash (USD), Calificación, N.º calificaciones, Incidencias, Última actividad.


GET /admin/reports/drivers/documents

Documentation & KYC, one row per driver × tracked document type (ID_FRONT, LICENSE, MEDICAL_CERT, RCV, ADDRESS_PROOF, SANITARY_CERT). Rows are sorted by days remaining ascending (expired/expiring first).

Query

Field Type Required Rules
kyc_state string no PENDING_KYC, PENDING_REVIEW, APPROVED, REJECTED
document string no one of the tracked document types
status string no vigente, por_vencer, vencido, or faltante
only_blocked boolean no only rows whose document blocks the driver
sort string no one of the sortable keys below; default days remaining ascending
direction string no asc or desc (default desc)
limit integer no 1–200, default 50
page integer no ≥ 1, default 1

Sortable sort keys: driver_name, id_number, kyc_state, kyc_approved_at, document, status, traffic_light, expires_at, days_remaining, blocks. Without sort, rows keep the default order (expired/expiring first).

Response 200

{
  "items": [
    {
      "driver_id": 7,
      "driver_name": "Luis Pérez",
      "id_number": "V12345678",
      "kyc_state": "APPROVED",
      "approved_by": null,
      "kyc_approved_at": "2026-02-05",
      "document": "LICENSE",
      "document_label": "Licencia",
      "status": "por_vencer",
      "traffic_light": "amarillo",
      "expires_at": "2026-08-15",
      "days_remaining": 26,
      "blocks": false
    }
  ],
  "meta": { "total": 360, "per_page": 50, "current_page": 1, "last_page": 8 },
  "totals": {
    "vigentes": 200,
    "por_vencer": 40,
    "vencidos": 30,
    "faltantes": 90,
    "conductores_bloqueados": 12
  }
}

status is vigente / por_vencer (within 30 days of expiry) / vencido / faltante. blocks is true for a document that is vencido, or faltante for a required type (ID_FRONT/LICENSE). approved_by is always null.

Errors

Status Body When
422 { "error": "ValidationError", … } Invalid filter value

GET /admin/reports/drivers/documents/export

Streams the filtered documentation report as CSV (text/csv); no JSON body on success.

Response 200 — a text/csv stream (reporte_documentacion_<timestamp>.csv) with the columns Conductor, Cédula, Estado KYC, Aprobado por, Fecha aprobación, Documento, Estado documento, Semáforo, Fecha vencimiento, Días restantes, Bloquea.


GET /admin/reports/drivers/performance

Performance, one row per driver × period. The default range is the last 3 months.

Query

Field Type Required Rules
date_from date no start of the range; span ≤ 366 days
date_to date no end of the range; >= date_from
granularity string no day, week, or month (default month)
driver_id integer no limit to one driver
min_deliveries integer no minimum deliveries to enter the ranking
rank_by string no deliveries (default), liters_delivered, earnings_usd, rating

Response 200

{
  "granularity": "month",
  "items": [
    {
      "period": "2026-07",
      "driver_id": 7,
      "driver_name": "Luis Pérez",
      "rank": 1,
      "online_hours": null,
      "notified": null,
      "accepted": 45,
      "acceptance_rate": null,
      "avg_response_minutes": null,
      "deliveries": 42,
      "completion_rate": 93.3,
      "own_cancellations": 1,
      "avg_delivery_minutes": 24.5,
      "liters_agreed": 43000,
      "liters_delivered": 42000,
      "liters_accuracy": 97.7,
      "earnings_usd": 341.04,
      "rating": 4.7,
      "incidents": 2
    }
  ]
}

rank is null for drivers below min_deliveries.

Errors

Status Body When
422 { "error": "ValidationError", "details": { "fieldErrors": { "date_to": ["…"] } } } Range wider than 366 days, or invalid filter

GET /admin/reports/drivers/performance/export

Streams the filtered performance report as CSV (text/csv); no JSON body on success.

Response 200 — a text/csv stream (reporte_desempeno_cisterneros_<timestamp>.csv) with the columns Período, Conductor, Posición, Horas en línea, Notificados, Aceptados, Tasa aceptación (%), T. medio respuesta (min), Entregas, Tasa completitud (%), Cancelaciones, T. medio entrega (min), Litros pactados, Litros entregados, Precisión litros (%), Ganancia (USD), Calificación, Incidencias.