Review and manage drivers (cisterneros): KYC, documents, status, certification, and
their wallets. Paths are relative to the /api/v1 prefix; these are back-office
endpoints requiring an admin token.
Requires an admin bearer token (see Admin auth). Admin only.
See Common errors.
For the list and stats, an admin only sees drivers with activity in their assigned
cities. Wallet money fields are USD (*_usd).
| Method | URI | Access | Description |
|---|---|---|---|
GET |
/admin/drivers/stats |
Admin | Counters: active / pending review / suspended |
GET |
/admin/drivers |
Admin | Paginated driver list with filters |
GET |
/admin/drivers/{driverId} |
Admin | Full driver detail (driver, vehicle, documents, wallet) |
GET |
/admin/drivers/{driverId}/documents |
Admin | KYC documents with validity state |
PATCH |
/admin/drivers/{driverId}/documents/{documentId}/approve |
Admin | Approve a single document |
PATCH |
/admin/drivers/{driverId}/documents/{documentId}/reject |
Admin | Reject a single document |
PATCH |
/admin/drivers/{driverId}/certify |
Admin | Mark the driver as certified |
PATCH |
/admin/drivers/{driverId}/status |
Admin | Change driver status (activate/suspend/ban) |
POST |
/admin/drivers/{driverId}/kyc/approve |
Admin | Approve KYC |
POST |
/admin/drivers/{driverId}/kyc/reject |
Admin | Reject KYC |
POST |
/admin/drivers/{driverId}/wallet/settle |
Admin | Settle the wallet balance into a payout |
POST |
/admin/drivers/{driverId}/wallet/adjust |
Admin | Manually credit/debit the wallet |
GET |
/admin/drivers/{driverId}/transactions |
Admin | Paginated wallet transactions |
GET |
/admin/drivers/{driverId}/transactions/export |
Admin | Export wallet transactions as CSV |
show, certify, kyc/approve, and kyc/reject all return the same full payload:
{
"driver": {
"id": 3,
"user": {
"id": 7,
"name": "Carlos Rodríguez",
"phone": "+584241001001",
"email": "carlos@example.com",
"created_at": "2026-05-01T09:00:00+00:00"
},
"status": "ACTIVE",
"kyc_state": "APPROVED",
"kyc_review_note": null,
"kyc_submitted_at": "2026-05-02T10:00:00+00:00",
"kyc_reviewed_at": "2026-05-03T11:00:00+00:00",
"is_online": true,
"avg_rating": 4.8,
"total_ratings": 25,
"completed_orders": 120,
"total_liters_delivered": 600000,
"available_liters": 5000,
"current_lat": 10.49,
"current_lng": -66.85,
"last_location_at": "2026-06-29T12:34:00+00:00",
"is_certified": true,
"created_at": "2026-05-01T09:00:00+00:00"
},
"vehicle": { "id": 4, "plate": "ABC-123", "capacity_liters": 5000, "status": "ACTIVE" },
"documents": [
{
"id": 1,
"type": "LICENSE",
"url": "https://…",
"status": "APPROVED",
"review_note": null,
"reviewed_at": "2026-05-03T11:00:00+00:00",
"expires_at": "2027-01-01T00:00:00+00:00",
"is_expired": false
}
],
"wallet": {
"balance_usd": 124.5,
"pending_payout_usd": 0,
"cash_debt_usd": 0,
"cash_debt_cap_usd": 50
}
}
vehicle and wallet are null when the driver has none.
Counters for the dashboard cards, scoped to the admin's cities.
Response 200
{ "total_active": 12, "total_pending_review": 3, "total_suspended": 1 }
Page-paginated driver list (newest first). See Pagination → page-based.
Query
| Field | Type | Required | Rules |
|---|---|---|---|
kyc_state |
string | no | PENDING_KYC, PENDING_REVIEW, APPROVED, REJECTED |
status |
string | no | PENDING_VERIFICATION, ACTIVE, SUSPENDED, BANNED |
is_online |
boolean | no | — |
min_rating |
number | no | between 0 and 5 |
q |
string | no | ≤ 80 chars; matches name, phone, or vehicle plate |
limit |
integer | no | 1–100, default 25 |
page |
integer | no | ≥ 1, default 1 |
Response 200
{
"items": [
{
"id": 3,
"name": "Carlos Rodríguez",
"phone": "+584241001001",
"status": "ACTIVE",
"kyc_state": "APPROVED",
"is_online": true,
"avg_rating": 4.8,
"completed_orders": 120,
"available_liters": 5000,
"balance_usd": 124.5
}
],
"meta": { "total": 42, "per_page": 25, "current_page": 1, "last_page": 2 }
}
Full driver detail. See the driver detail object.
Response 200 — { "driver": { … }, "vehicle": { … }, "documents": [ … ], "wallet": { … } }.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
Lists the driver's KYC documents with their expiry state.
Response 200
{
"driver_id": 3,
"items": [
{
"id": 1,
"type": "LICENSE",
"url": "https://…",
"approval_status": "APPROVED",
"review_note": null,
"reviewed_at": "2026-05-03T11:00:00+00:00",
"expires_at": "2027-01-01T00:00:00+00:00",
"validity_state": "vigente",
"days_to_expire": 186
}
]
}
validity_state is one of vigente, por_vencer (expires within 30 days), vencido
(past expires_at), or sin_vencimiento (no expiry). days_to_expire is null when
the document has no expires_at.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
Marks a single document as approved.
Response 200
{
"document": {
"id": 1,
"type": "LICENSE",
"url": "https://…",
"status": "APPROVED",
"review_note": null,
"reviewed_at": "2026-06-29T12:00:00+00:00",
"expires_at": "2027-01-01T00:00:00+00:00"
}
}
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
404 |
{ "error": "DocumentNotFound" } |
Document not found for this driver |
Rejects a single document with a reason.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
reason |
string | yes | 10–500 chars |
Response 200 — same { "document": { … } } shape with status: "REJECTED" and
review_note set.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
404 |
{ "error": "DocumentNotFound" } |
Document not found for this driver |
Marks the driver as certified. Returns the full driver detail object.
Response 200 — { "driver": { … }, "vehicle": { … }, "documents": [ … ], "wallet": { … } }.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
Changes the driver's lifecycle status.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
status |
string | yes | ACTIVE, SUSPENDED, or BANNED |
reason |
string | conditional | ≤ 500 chars; required when suspending or banning |
Response 200
{ "driver": { "id": 3, "status": "SUSPENDED" } }
Errors
| Status | Body | When |
|---|---|---|
422 |
{ "error": "ReasonRequired", "message": "…" } |
Suspending/banning without a reason |
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
422 |
{ "error": "AlreadyInStatus", "message": "…" } |
Driver is already in the requested status |
422 |
{ "error": "NoVehicle", "message": "…" } |
Activating a driver that has no vehicle |
Approves a KYC submission. The driver must be in PENDING_REVIEW. Returns the full
driver detail object.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
note |
string | no | ≤ 500 chars |
Response 200 — { "driver": { … }, "vehicle": { … }, "documents": [ … ], "wallet": { … } }
with kyc_state: "APPROVED".
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
422 |
{ "error": "InvalidKycState", "message": "…" } |
Driver is not in PENDING_REVIEW |
Rejects a KYC submission with a required reason. The driver must be in PENDING_REVIEW.
Returns the full driver detail object.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
reason |
string | yes | 10–500 chars |
Response 200 — { "driver": { … }, "vehicle": { … }, "documents": [ … ], "wallet": { … } }
with kyc_state: "REJECTED".
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
422 |
{ "error": "InvalidKycState", "message": "…" } |
Driver is not in PENDING_REVIEW |
Pays out the entire current wallet balance as a PENDING payout.
Response 200
{
"payout": {
"id": 10,
"amount_usd": 124.5,
"method": "PAGO_MOVIL",
"status": "PENDING",
"scheduled_at": null
}
}
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
422 |
{ "error": "NoWallet", "message": "…" } |
The driver has no wallet |
422 |
{ "error": "NoPayoutMethod", "message": "…" } |
No payout method configured |
422 |
{ "error": "InsufficientBalance", "message": "…" } |
Balance is zero or negative |
Applies a manual credit or debit. A debit cannot push the balance below zero.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
type |
string | yes | credit or debit |
amount |
number | yes | ≥ 0.01 (USD) |
reason |
string | yes | 10–500 chars |
Response 200
{
"transaction": {
"id": 55,
"type": "MANUAL_ADJUSTMENT",
"amount_usd": 10.0,
"balance_after_usd": 134.5,
"description": "credit manual: ajuste por reclamo",
"created_at": "2026-06-29T12:00:00+00:00"
}
}
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
Page-paginated wallet transactions (newest first). See
Pagination → page-based. A driver with no
wallet returns an empty list with 200.
Query
| Field | Type | Required | Rules |
|---|---|---|---|
type |
string | no | one of: ORDER_EARNING, PAYOUT_SENT, MANUAL_ADJUSTMENT |
from |
date | no | filter created_at >= |
to |
date | no | filter created_at <= |
limit |
integer | no | 1–100, default 25 |
page |
integer | no | ≥ 1, default 1 |
Response 200
{
"items": [
{
"id": 55,
"type": "ORDER_EARNING",
"is_credit": true,
"amount_usd": 16.24,
"balance_after_usd": 124.5,
"exchange_rate_amount": 540.043,
"description": "Ganancia pedido #42",
"order_id": 42,
"payout_id": null,
"created_at": "2026-06-29T12:00:00+00:00"
}
],
"meta": { "total": 80, "per_page": 25, "current_page": 1, "last_page": 4 }
}
exchange_rate_amount is the BCV VES rate (Bs/USD) snapshot of the related order;
null for movements without an order (PAYOUT_SENT, MANUAL_ADJUSTMENT).
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
Streams the filtered wallet transactions as a CSV download (Content-Type: text/csv); there is no JSON body. Accepts the same type, from, and to
filters as the list. Columns: id, fecha, tipo, credito, monto_usd,
saldo_despues_usd, tasa_cambio, descripcion, order_id, payout_id.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |