Stations

The crowd-sourced filling-station directory: find nearby stations, read their live status, post traffic-light reports, and chat on a station's comment wall. Paths are relative to the /api/v1 prefix; all routes require Authorization: Bearer {token}.

See Common errors. Comment lists are cursor-paginated — see Pagination.

Endpoints

Method URI Role Description
GET /stations/nearby any Nearby stations within a radius (throttled)
GET /stations any Nearby stations (alias of /stations/nearby)
POST /stations/report DRIVER Report a station's status
GET /stations/{stationId} any Station detail with recent reports
POST /stations/{stationId}/reports DRIVER Report a station (REST alias of /stations/report)
GET /stations/{stationId}/comments any Station comment wall (cursor)
POST /stations/{stationId}/comments DRIVER Post a comment (throttled)
DELETE /stations/{stationId}/comments/{commentId} DRIVER Delete your own comment

{stationId} and {commentId} are numeric. Reporting and commenting are restricted to drivers; everyone authenticated can read.


GET /stations/nearby

Stations within a bounding box around a point. /stations is an exact alias.

Rate limit: 20 requests / minute.

Query

Field Type Required Rules
lat number yes between −90 and 90
lng number yes between −180 and 180
radiusKm number no > 0, ≤ 100; defaults to 10
type string no WATER or FUEL

Response 200

{
  "stations": [
    {
      "id": 7,
      "name": "E/S Las Mercedes",
      "address": "Av. Principal, Las Mercedes",
      "latitude": 10.487,
      "longitude": -66.88,
      "city": "Caracas",
      "station_type": "WATER",
      "is_verified": true,
      "is_active": true,
      "current_status": {
        "current_color": "GREEN",
        "confidence": 0.8,
        "report_count": 4,
        "avg_wait_minutes": 12,
        "last_report_at": "2026-06-26T12:00:00+00:00"
      }
    }
  ]
}

current_status is null until the station has at least one report.


GET /stations

Alias of GET /stations/nearby — identical query, response, and 20 req/min throttle.


POST /stations/report

A driver posts a traffic-light report for a station. Re-reporting the same station is blocked by a 15-minute cooldown per driver. POST /stations/{stationId}/reports is the REST alias (it supplies stationId from the path instead of the body).

Request body

Field Type Required Rules
stationId integer yes required (supplied by path on the /reports alias)
color string yes GREEN, YELLOW, RED, or CLOSED
waitMinutes integer no 0–240
comment string no ≤ 280 chars
driverLat number yes between −90 and 90
driverLng number yes between −180 and 180

Response 200

{
  "report": {
    "id": 51,
    "station_id": 7,
    "driver_id": 3,
    "color": "YELLOW",
    "wait_minutes": 20,
    "comment": "Cola moderada",
    "driver_lat": 10.49,
    "driver_lng": -66.85,
    "created_at": "2026-06-26T12:05:00+00:00"
  },
  "confidence": 0.6
}

Errors

Status Body When
404 { "error": "DriverNotFound" } The caller has no driver profile
429 { "error": "Cooldown", "message": "…", "retryAfterMinutes": 15 } Reported this station within the cooldown window

POST /stations/{stationId}/reports

REST alias of POST /stations/report: stationId comes from the path, the rest of the body and all responses/errors are identical.


GET /stations/{stationId}

Full station detail plus its 20 most recent reports.

Response 200

{
  "station": {
    "id": 7,
    "name": "E/S Las Mercedes",
    "address": "Av. Principal, Las Mercedes",
    "latitude": 10.487,
    "longitude": -66.88,
    "city": "Caracas",
    "station_type": "WATER",
    "is_verified": true,
    "is_active": true,
    "current_status": { "current_color": "GREEN", "confidence": 0.8, "report_count": 4 }
  },
  "reports": [
    {
      "id": 51,
      "color": "YELLOW",
      "waitMinutes": 20,
      "comment": "Cola moderada",
      "createdAt": "2026-06-26T12:05:00+00:00"
    }
  ]
}

Errors

Status Body When
404 { "error": "StationNotFound" } Unknown or inactive station

GET /stations/{stationId}/comments

Cursor-paginated comment wall, newest first. See Pagination → cursor-based.

Query

Field Type Required Rules
limit integer no 1–100; defaults to 30
cursor string no opaque cursor from next_cursor

Response 200

{
  "items": [
    {
      "id": 12,
      "station_id": 7,
      "author": { "id": 3, "name": "Carlos Rodríguez", "role": "DRIVER" },
      "content": "Ahora mismo sin cola.",
      "created_at": "2026-06-26T12:10:00+00:00"
    }
  ],
  "next_cursor": "eyJpZCI6MTF9",
  "has_more": true
}

Errors

Status Body When
404 { "error": "StationNotFound", "message": "…" } Unknown or inactive station

POST /stations/{stationId}/comments

A driver posts a comment to the wall. Rate limit: 10 requests / minute.

Request body

Field Type Required Rules
content string yes 1–500 chars

Response 201

{
  "comment": {
    "id": 13,
    "station_id": 7,
    "author": { "id": 3, "name": "Carlos Rodríguez", "role": "DRIVER" },
    "content": "Acaban de abrir.",
    "created_at": "2026-06-26T12:12:00+00:00"
  }
}

Errors

Status Body When
404 { "error": "StationNotFound", "message": "…" } Unknown or inactive station

DELETE /stations/{stationId}/comments/{commentId}

Deletes a comment. Only the comment's author may delete it.

Response 200{ "ok": true }.

Errors

Status Body When
403 { "error": "Forbidden", "message": "…" } The caller is not the comment's author
404 { "error": "NotFound", "message": "…" } Unknown comment

Examples

# Nearby water stations
curl "/api/v1/stations/nearby?lat=10.487&lng=-66.88&radiusKm=5&type=WATER" \
  -H "Authorization: Bearer {token}"

# Driver: report a station (plain endpoint)
curl -X POST /api/v1/stations/report \
  -H "Authorization: Bearer {driver_token}" \
  -H "Content-Type: application/json" \
  -d '{"stationId": 7, "color": "YELLOW", "waitMinutes": 20, "driverLat": 10.49, "driverLng": -66.85}'

# Driver: comment on a station
curl -X POST /api/v1/stations/7/comments \
  -H "Authorization: Bearer {driver_token}" \
  -H "Content-Type: application/json" \
  -d '{"content": "Ahora mismo sin cola."}'