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/adjust |
Admin | Manually credit/debit the wallet |
POST |
/admin/drivers/{driverId}/wallet/settle-cash-debt |
Admin | Settle the driver's cash debt |
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
},
"payout_config": {
"method": "PAGO_MOVIL",
"bank_code": "0102",
"id_number": "12345678",
"phone": "+584241234567",
"account_number": null,
"account_type": null,
"updated_at": "2026-06-01T10:00:00+00:00"
}
}
vehicle, wallet, and payout_config are null when the driver has none.
payout_config.method is PAGO_MOVIL or BANK_TRANSFER. For PAGO_MOVIL, bank_code + id_number + phone are set and account_number + account_type are null. For BANK_TRANSFER, account_number + account_type are set.
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 |
Applies a manual credit or debit. A debit may take the balance negative, so balance_after_usd can be negative.
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",
"direction": "CREDIT",
"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 |
Settles the driver's outstanding cash debt (cashDebtUSD). mode picks the
accounting: external_payment lowers only the cash debt (balance_after_usd
unchanged); offset_earnings lowers the cash debt and the balance by the same
amount, and requires the driver's withdrawable earnings to cover it. When
amount is omitted the full outstanding debt is settled.
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
mode |
string | yes | external_payment or offset_earnings |
amount |
number | no | ≥ 0.01 (USD); ≤ current cash debt; omitted settles the full debt |
reason |
string | yes | 10–500 chars |
Response 200
{
"transaction": {
"id": 71,
"type": "CASH_DEBT_PAYMENT",
"direction": "CREDIT",
"amount_usd": 3.6,
"balance_after_usd": 124.5,
"description": "Saldo de deuda en efectivo (pago externo): pagó en oficina",
"created_at": "2026-06-29T12:00:00+00:00"
},
"wallet": {
"balance_usd": 124.5,
"cash_debt_usd": 0.0,
"can_go_online": true
}
}
transaction.type is CASH_DEBT_PAYMENT for external_payment (direction
CREDIT) or CASH_DEBT_OFFSET for offset_earnings (direction DEBIT).
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |
409 |
{ "error": "SettlementInProgress", "message": "…" } |
Another settle request for this driver is being processed concurrently |
409 |
{ "error": "PayoutInProgress", "message": "…" } |
A generated-but-unpaid settlement receipt already accounts for this debt |
422 |
{ "error": "NoCashDebt", "message": "…" } |
The driver has no outstanding cash debt |
422 |
{ "error": "AmountExceedsCashDebt", "message": "…" } |
amount is greater than the current cash debt |
422 |
{ "error": "InsufficientEarnings", "message": "…" } |
mode is offset_earnings but the withdrawable earnings do not cover the amount |
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, PROMO_BONUS, PROMO_REIMBURSEMENT |
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",
"direction": "CREDIT",
"is_credit": true,
"amount_usd": 16.24,
"balance_after_usd": 124.5,
"exchange_rate_amount": 540.043,
"description": "Ganancia pedido #42",
"order_id": 42,
"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,
PROMO_BONUS). PROMO_BONUS is a milestone campaign reward and
PROMO_REIMBURSEMENT is the cash a client's promotional credit took off a cash
order; both are CREDIT.
direction is CREDIT (adds to the balance) or DEBIT (subtracts); is_credit is
true exactly when direction is CREDIT.
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.
Errors
| Status | Body | When |
|---|---|---|
404 |
{ "error": "DriverNotFound" } |
No driver with that id |