Drivers

Driver-side (cisternero) operations: going online, performance and earnings stats, discovering nearby orders, and the driver's own order history and receipts. Paths are relative to the /api/v1 prefix; every route requires Authorization: Bearer {token} and the DRIVER role.

See Common errors. The customer-facing order flow lives under Orders; see also the order lifecycle and driver wallet & cash debt.

Endpoints

Method URI Role Description
GET /drivers/me/stats DRIVER Earnings stats (week / month / all-time)
GET /driver/stats DRIVER Performance stats by period (+ rating)
GET /driver/surplus DRIVER My surplus listings with status
GET /driver/available-orders DRIVER Nearby broadcasting orders
POST /driver/online DRIVER Go online / offline
GET /driver/orders/active DRIVER My current active order
GET /driver/orders/{orderId}/receipt DRIVER Driver receipt for a delivered order
GET /driver/orders DRIVER My order history (cursor)

Endpoints that resolve the driver from the token return 404 DriverNotFound when the caller has no driver profile. Money fields end in _usd (decimal).


GET /drivers/me/stats

Aggregated delivery stats over fixed windows, plus the all-time totals and the driver-bonus counters.

Response 200

{
  "week": {
    "trips": 8, "liters": 40000, "earningsUSD": 130.0,
    "solidaryUSD": 1.3, "solidaryLTS": 260,
    "matchedByAguitaUSD": 1.3, "matchedByAguitaLTS": 260, "totalImpactLTS": 520
  },
  "month": {
    "trips": 32, "liters": 160000, "earningsUSD": 520.0,
    "solidaryUSD": 5.2, "solidaryLTS": 1040,
    "matchedByAguitaUSD": 5.2, "matchedByAguitaLTS": 1040, "totalImpactLTS": 2080
  },
  "allTime": {
    "trips": 120,
    "liters": 600000,
    "earningsUSD": 1950.0,
    "solidaryUSD": 19.5,
    "solidaryLTS": 3900,
    "matchedByAguitaUSD": 19.5,
    "matchedByAguitaLTS": 3900,
    "totalImpactLTS": 7800,
    "bonusQualifyingTrips": 45,
    "bonusMinReceives": 40
  }
}
Field Type Description
earningsUSD number Historical driver earnings (sum of driver_receives across all delivered orders, independent of wallet payout transactions)
solidaryUSD number The driver's own contribution to the fund
solidaryLTS integer The same, in liters of water funded
matchedByAguitaUSD number What Agüita contributed mirroring this driver
matchedByAguitaLTS integer The same, in liters
totalImpactLTS integer Liters funded by the driver's slice plus Agüita's match

*LTS fields express money as liters of water funded, at the rate in aguita.solidary.usd_per_1000_liters (default: 5 USD per 1000 L). Integer, rounded to the nearest liter; 0 turns the metric off.

matchedByAguitaUSD is summed from the driver's delivered orders, not assumed equal to solidaryUSD: deliveries before 2026-06-08 predate the mirror and were not matched, so for a veteran driver the two figures differ.

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile

GET /driver/stats

Performance for a single period, with the driver's rating. acceptance_rate is currently always null.

Query

Field Type Required Rules
period string no day, week, month, total, or all; defaults to all

Response 200 — for a specific period (e.g. ?period=week):

{
  "rating": { "average": 4.8, "total": 96 },
  "acceptance_rate": null,
  "period": "week",
  "stats": {
    "trips": 8, "liters": 40000, "earningsUSD": 130.0,
    "solidaryUSD": 1.3, "solidaryLTS": 260,
    "matchedByAguitaUSD": 1.3, "matchedByAguitaLTS": 260, "totalImpactLTS": 520
  },
  "previous": {
    "trips": 6, "liters": 30000, "earningsUSD": 98.0,
    "solidaryUSD": 0.98, "solidaryLTS": 196,
    "matchedByAguitaUSD": 0.98, "matchedByAguitaLTS": 196, "totalImpactLTS": 392
  }
}

The solidarity fields carry the same meaning as in GET /drivers/me/stats above.

With period=all, the response instead carries day, week, month, and total breakdowns side by side. previous (a comparison window) is omitted for period=total.

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile

GET /driver/surplus

All of the caller's surplus listings (active, reserved, expired, cancelled) with a status. See Surplus for the listing shape.

Response 200

{
  "listings": [
    {
      "id": 5,
      "available_liters": 5000,
      "remaining_liters": 0,
      "price_per_liter_usd": 0.02,
      "total_price_usd": 100.0,
      "address": "Av. Principal, Las Mercedes",
      "expires_at": "2026-06-26T14:00:00+00:00",
      "status": "RESERVADA"
    }
  ]
}

status is one of ACTIVA, RESERVADA, EXPIRADA, or CANCELADA.


GET /driver/available-orders

Nearby BROADCASTING orders the driver can still serve, ordered by distance. Requires the driver to be ACTIVE and online.

Query

Field Type Required Rules
latitude number yes between −90 and 90
longitude number yes between −180 and 180

Response 200

{
  "items": [
    {
      "id": 42,
      "address": "Av. Principal, Las Mercedes",
      "address_reference": "Frente a la panadería, portón azul",
      "latitude": 10.487,
      "longitude": -66.88,
      "liters_requested": 5000,
      "water_type": "POTABLE",
      "base_price_usd": 10.0,
      "aguita_revenue_usd": 1.8,
      "driver_solidary_usd": 0.0,
      "driver_gross_usd": 8.2,
      "driver_receives_usd": 8.2,
      "client_pays_usd": 10.0,
      "notes": null,
      "distance_km": 1.2,
      "expires_at": "2026-06-26T12:05:00+00:00",
      "created_at": "2026-06-26T12:00:00+00:00"
    }
  ]
}

Each item carries the DRIVER money view (same fields as GET /driver/orders/active): aguita_revenue_usd, driver_solidary_usd, driver_gross_usd, driver_receives_usd. client_pays_usd is present only when the order is paid in cash (so the driver knows how much to collect on delivery); it is omitted for online-paid orders.

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile
403 { "error": "DriverNotActive", "message": "…" } Driver status is not ACTIVE
403 { "error": "DriverOffline", "message": "Debe estar online." } Driver is offline

POST /driver/online

Toggles the driver online or offline. Going online requires location and a liters declaration, and checks that the driver is ACTIVE, under the cash-debt cap, and not exceeding the vehicle's capacity.

Request body

Field Type Required Rules
online boolean yes —
latitude number conditional required when online=true; between −90 and 90
longitude number conditional required when online=true; between −180 and 180
liters integer conditional required when online=true; ≥ 1

Response 200

{
  "driver": {
    "id": 3,
    "isOnline": true,
    "availableLiters": 5000,
    "remainingLiters": 5000,
    "currentLat": 10.49,
    "currentLng": -66.85,
    "lastLocationAt": "2026-06-26T11:55:00+00:00"
  }
}

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile
403 { "error": "DriverNotActive", "message": "…" } Driver status is not ACTIVE
403 { "error": "DebtExceedsLimit", "message": "…", "cashDebtUsd": 25.0, "cashDebtCapUsd": 20.0 } Cash debt exceeds the cap
422 { "error": "NoVehicle", "message": "…" } No vehicle with a registered capacity
422 { "error": "LitersExceedCapacity", "message": "…", "capacityLiters": 5000 } Declared liters exceed the tank capacity

GET /driver/orders/active

The driver's current active order, or null. The payload is the order in the DRIVER view (see Orders → the order object); the delivery_pin is hidden until the order is paid (CONFIRMED/IN_PROGRESS/ARRIVED).

Response 200 — { "order": { … } } or { "order": null }.


GET /driver/orders/{orderId}/receipt

The driver's receipt for a delivered order they served — the driver-side money split only (no client amounts).

Response 200

{
  "receipt": {
    "order_id": 42,
    "status": "DELIVERED",
    "delivered_at": "2026-06-26T12:40:00+00:00",
    "liters_requested": 5000,
    "actual_liters": 5000,
    "water_type": "POTABLE",
    "payment_method": "CASH_USD",
    "is_fully_promoted": false,
    "breakdown": {
      "driver_gross_usd": 16.4,
      "driver_solidary_usd": 0.16,
      "driver_receives_usd": 16.24,
      "aguita_solidary_usd": 0.16,
      "platform_covers_driver": false,
      "platform_subsidy_usd": 0.0
    },
    "client": { "id": 1, "name": "Ana Martínez", "phone": "+584241000001" }
  }
}

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile
404 { "error": "OrderNotFound" } Unknown order
403 { "error": "Forbidden" } The order was not served by this driver
409 { "error": "OrderNotDelivered", "message": "…" } Order not delivered yet

GET /driver/orders

Cursor-paginated history of the driver's orders, newest first. See Pagination → cursor-based.

Query

Field Type Required Rules
status string no one of WAITING_FOR_PAYMENT, CONFIRMED, IN_PROGRESS, ARRIVED, DELIVERED, CANCELLED, EXPIRED
date_from date no filters created_at ≥
date_to date no after or equal to date_from; filters created_at ≤
limit integer no 1–100; defaults to 25
cursor string no opaque cursor from next_cursor

Response 200

{
  "items": [
    {
      "id": 42,
      "status": "DELIVERED",
      "liters_requested": 5000,
      "water_type": "POTABLE",
      "address": "Av. Principal, Las Mercedes",
      "driver_receives_usd": 16.24,
      "payment_method": "CASH_USD",
      "client": { "id": 1, "name": "Ana Martínez" },
      "created_at": "2026-06-26T12:00:00+00:00",
      "delivered_at": "2026-06-26T12:40:00+00:00"
    }
  ],
  "next_cursor": "eyJpZCI6NDF9",
  "has_more": true
}

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile

Examples

# Go online with 5000 L at the current location
curl -X POST /api/v1/driver/online \
  -H "Authorization: Bearer {driver_token}" \
  -H "Content-Type: application/json" \
  -d '{"online": true, "latitude": 10.49, "longitude": -66.85, "liters": 5000}'

# Discover nearby broadcasting orders
curl "/api/v1/driver/available-orders?latitude=10.49&longitude=-66.85" \
  -H "Authorization: Bearer {driver_token}"

# This week's performance
curl "/api/v1/driver/stats?period=week" -H "Authorization: Bearer {driver_token}"