All APIs are consumed through the Marmaradar gateway. This site (api.marmaradar.com) hosts documentation only — send API requests to the gateway base URL below.
http://35.239.129.237:8081http://127.0.0.1:8081https://api.marmaradar.com/docs/apiusage.html/openapi.json — machine-readable subset; this page is the full usage guide.
Most endpoints require a JWT. Send it in the header:
Authorization: Bearer <your_access_token>
Obtain a token via the Auth API (no token required). When the access token expires, call POST /v1/auth/refresh with the refresh_token.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /v1/auth/register |
None | Register with email and password (min. 8 characters). Returns access + refresh tokens and user info. |
| POST | /v1/auth/login |
None | Email/password login; returns access + refresh tokens and user info. |
| POST | /v1/auth/refresh |
None | Rotate tokens. Body: refresh_token. |
| POST | /v1/auth/oauth |
None | Google/Apple sign-in. Body: provider (google | apple), id_token, optional nonce (Apple). |
| POST | /v1/auth/forgot-password |
None | Request password reset email. Body: email. Response: {"ok": true}. |
| POST | /v1/auth/reset-password |
None | Complete reset with token (from email) and password (min. 8). Response: {"ok": true}. |
| GET | /reset-password |
None | HTML reset form (query: token). Not a JSON API. |
All paths below are relative to the gateway base URL. Protected routes expect Authorization: Bearer <access_token>.
Route prefixes:
/v1/auth/* · /v1/users/* · /v1/drives/* · /v1/leaderboard/v1/cameras/* · /v1/corridors/* · /v1/sync · /v1/uploads/*/v1/reports/* · /v1/live-reports/* · /v1/eta/* · /v1/amenities/* · /v1/tts/*/v1/auth/* — Register, login, refresh, OAuth, forgot/reset password (see table above). No Bearer token required.
/v1/cameras/* · /v1/corridors/* · /v1/sync — Public map data. No auth.
/v1/cameras/nearby — Nearby speed cameras. Query: lat, lon (required), radius_m (default 1000, max 5000), region (default bursa)/v1/corridors/nearby — Nearby average-speed corridors. Query: lat, lon, region/v1/sync — Delta sync for a bbox. Query: bbox (west,south,east,north, required), region, optional since (RFC3339)/v1/uploads/avatars/{file} — Public avatar image. No auth. Cached 24h./v1/users/* · /v1/leaderboard — Require Bearer token.
/v1/users/me — Current profile (id, email, username, profile_picture_url, vehicle_type, vehicle_color)/v1/users/me — Partial update: username, vehicle_type, vehicle_color (see §3.2)/v1/users/me/profile-picture — Upload avatar (multipart/form-data, field file; JPEG/PNG/WebP, max 2 MB)/v1/users/me/stats — Lifetime stats, rank/XP, streak, achievements/v1/leaderboard — Top 100 + caller rank. Query: category = distance | reports (required)/v1/drives/* — Recorded trips. Requires Bearer token.
/v1/drives — Upload a drive (points + optional name). Returns id, length_m, point_count/v1/drives — List my drives (summaries)/v1/drives/{id} — Drive detail with points / snapped path/v1/drives/{id} — Rename. Body: { "name": "..." }. Returns 204/v1/reports/* — Requires Bearer token.
/v1/reports — Create or merge a mobile radar report. Body: lat, lon, optional heading_deg, region/v1/reports/{id}/votes — Vote. Body: value (1 / -1), lat, lon (voter position)/v1/live-reports/* — Short-lived hazards (police / accident).
/v1/live-reports/active — Active reports (pending + confirmed). No auth/v1/live-reports — Create. Body: lat, lng, report_type (police | accident). Bearer/v1/live-reports/{id}/vote — Vote. Body: is_upvote (bool). BearerAll require Bearer token.
/v1/eta/cameras — Driving ETA to nearby cameras (max 3 destinations). Body: origin, destinations[]/v1/amenities/cells — Gas/rest stops by grid cells (max 3). Body: cells[], optional types/v1/tts/speak — Synthesize Turkish alert audio (audio/mpeg). Body: phrase_key, params/v1/tts/catalog — Catalog of cacheable TTS phrase variantsJSON uses snake_case property names. Date/time values are ISO 8601 (RFC3339). Errors return {"error": "human-readable message"} with an appropriate HTTP status.
| Endpoint | Properties (JSON) |
|---|---|
| POST /v1/auth/register | email, password (min. 8) |
| POST /v1/auth/login | email, password |
| POST /v1/auth/refresh | refresh_token |
| POST /v1/auth/oauth | provider, id_token, nonce (optional, Apple) |
| POST /v1/auth/forgot-password | email |
| POST /v1/auth/reset-password | token, password (min. 8) |
AuthResult (register / login / refresh / oauth){
"access_token": "string (JWT)",
"refresh_token": "string",
"expires_in": 900,
"user": { "id": "uuid", "email": "string" }
}
UserProfileResponse — GET/PATCH /v1/users/me, profile-picture upload:
{
"id": "uuid",
"email": "string",
"username": "string | null",
"profile_picture_url": "/v1/uploads/avatars/{id}.jpg | null",
"vehicle_type": "sedan | hatchback | station_wagon | kamyon | tir",
"vehicle_color": "#RRGGBB"
}
UpdatePreferencesRequest — PATCH /v1/users/me (partial; omit unchanged fields):
{
"username": "string (optional; a-z0-9_; 3–20; unique)",
"vehicle_type": "sedan | hatchback | station_wagon | kamyon | tir",
"vehicle_color": "#RRGGBB"
}
profile_picture_url is a relative path on the gateway. Display as http://35.239.129.237:8081 + path. Avatars need no Bearer token.
GET /v1/leaderboard?category=distance|reports returns:
{
"category": "distance",
"entries": [
{
"rank": 1,
"user_id": "uuid",
"username": "string",
"profile_picture_url": "string | null",
"vehicle_type": "sedan",
"vehicle_color": "#E8262D",
"value": 152340.5
}
],
"me": { "rank": 142, "user_id": "uuid", "username": "string", "...": "...", "in_top": false }
}
value is meters for distance, contribution count for reports. Top 100 plus always the caller’s me row.
Create — POST /v1/drives:
{
"started_at": "2026-01-01T12:00:00Z",
"ended_at": "2026-01-01T12:30:00Z",
"name": "string | null",
"points": [
{ "lat": 0, "lon": 0, "speed_mps": 0, "recorded_at": "2026-01-01T12:00:00Z" }
]
}
List/detail include summary fields (length_m, point_count, speed stats). Detail also returns points[] and optional snapped_points[].
Create report — POST /v1/reports: lat, lon, optional heading_deg, region. Response includes id, status, votes, expires_at, merged.
Vote — POST /v1/reports/{id}/votes: value (1|-1), lat, lon.
Live report — POST /v1/live-reports: lat, lng, report_type (police|accident). Active list returns id, lat, lng, report_type, verification_state, weighted_score, timestamps.
ETA — POST /v1/eta/cameras:
{
"origin": { "lat": 0, "lon": 0 },
"destinations": [{ "camera_id": "string", "lat": 0, "lon": 0 }]
}
Response: [{ "camera_id", "distance_m", "duration_sec", "status" }]. Max 3 destinations. 503 if Matrix API unavailable.
Amenities — POST /v1/amenities/cells: cells[] with lat_index/lon_index; optional types (gas_station, rest_stop). Max 3 cells.
TTS speak — phrase_key examples: camera.fixed, camera.mobile, report.police, corridor.warn, corridor.over. Distance phrases need params.distance_m. Response body is raw audio/mpeg.
Validation or business errors typically return 400 with {"error": "string"}. Unauthorized: 401. Forbidden: 403. Not found: 404. Conflict (e.g. username taken, invalid vote): 409. Rate limited: 429.
Allowed origins include https://marmaradar.com, https://www.marmaradar.com, https://api.marmaradar.com, and localhost (e.g. http://localhost:5173). For other origins, coordinate with the API owner.
GET {gateway}/health — Returns 200 with {"status":"ok"} if the API is up. No authentication required.
http://35.239.129.237:8081 in production) for all API calls — not this docs host alone for data requests.POST /v1/auth/login, POST /v1/auth/register, or POST /v1/auth/oauth.POST /v1/auth/refresh when the access token expires.Authorization: Bearer <token> on every protected request.Content-Type: application/json for JSON bodies (except profile photo upload).401 (re-authenticate) and 403/409/429 appropriately.profile_picture_url in <img src> (no Bearer on image requests).Last updated: 2026-09 — switched docs UI to gateway usage guide. When new APIs or DTOs change, update this page and regenerate OpenAPI via backend/scripts/generate-openapi.sh for annotated endpoints.