Random Forest Rangers

SafeWalk API
Reference

REST API powering crowdsourced pedestrian safety navigation for Indian cities. Built with FastAPI + Supabase. Deployed on Render.

Live on Render
FastAPI 0.135
Python 3.x
MIT License

📖 Introduction

The SafeWalk API lets clients report street hazards, retrieve hazard data with optional location filtering, calculate safety scores, confirm community reports, and manage user accounts. All responses are JSON. Form-data is used only for hazard creation (to support image upload).

Production Base URL
BASE URL https://safewalk-95z8.onrender.com
Local Development Base URL
LOCAL http://localhost:8000
Note: The Render free tier spins down after 15 minutes of inactivity. The first request may take 10–30 seconds to wake the server. Subsequent requests are fast.

Environment Variables

Copy .env.example to .env and fill in these values before running locally.

SUPABASE_URL Your Supabase project URL — found in Project Settings → API
SUPABASE_SECRET_KEY Service role key from Supabase. Has full DB access — never expose client-side.
SUPABASE_PUBLISHABLE_KEY Anon/public key for client-side use (limited permissions).
JWT_SECRET Secret key used to sign and verify JWT tokens. Use a long random string.

💚 Health Check

Verify the API server is online and responsive.

GET
/
Returns server status and uptime confirmation.
No parameters
200 Response
JSON
{
  "status": "online",
  "message": "SafeWalk Backend is active!"
}
Example Request
cURL
curl https://safewalk-95z8.onrender.com/

🗺 Get Hazards

Fetch all hazards from the database. Optionally filter by geographic location using a bounding box radius.

GET
/hazards
Returns all hazards, or those within a radius of a given coordinate.
Query Parameters
Parameter Type Required Description
latitude float optional Latitude of the centre point. Must be paired with longitude to activate location filter.
longitude float optional Longitude of the centre point. Must be paired with latitude.
radius float optional Bounding box radius in degrees. Default: 0.01 (~1 km). Use 0.01 for 1 km, 0.05 for ~5 km.
200 Response
JSON
{
  "hazards": [
    {
      "id": "uuid-string",
      "type": "manhole",
      "description": "Open manhole near bus stop",
      "latitude": 13.0827,
      "longitude": 80.2707,
      "photo_url": "https://...",
      "reported_by": "vishaal",
      "confirmed_count": 3,
      "created_at": "2026-03-29T14:22:00+00:00"
    }
  ],
  "count": 1
}
Example Requests
cURL — All Hazards
curl https://safewalk-95z8.onrender.com/hazards
cURL — Nearby (Chennai centre, 1 km)
curl "https://safewalk-95z8.onrender.com/hazards?latitude=13.0827&longitude=80.2707&radius=0.01"

🕳 Report Hazard

Submit a new hazard report. Optionally attach a photo — it will be uploaded to Supabase Storage and a public URL returned.

POST
/hazards
Creates a new hazard record in the database. Accepts multipart/form-data.
Content-Type: This endpoint uses multipart/form-data, not JSON, to support optional image upload.
Form Fields
Field Type Required Description
type string required Hazard category. See Hazard Types reference.
description string required Human-readable description of the hazard.
latitude float required Latitude of the hazard location.
longitude float required Longitude of the hazard location.
reported_by string required Username or identifier of the person reporting.
image file optional Photo of the hazard. Accepted: jpg, jpeg, png. Validated server-side with Pillow.
201 Response
JSON
{
  "message": "Hazard reported successfully!",
  "data": [
    {
      "id": "uuid-string",
      "type": "manhole",
      "description": "Open drain on footpath",
      "latitude": 13.0827,
      "longitude": 80.2707,
      "photo_url": "https://supabase.co/storage/...",
      "reported_by": "vishaal",
      "confirmed_count": 0,
      "created_at": "2026-03-31T09:00:00+00:00"
    }
  ]
}
Example Request
cURL
curl -X POST https://safewalk-95z8.onrender.com/hazards \
  -F "type=manhole" \
  -F "description=Open drain near Anna Nagar signal" \
  -F "latitude=13.0850" \
  -F "longitude=80.2101" \
  -F "reported_by=vishaal" \
  -F "image=@/path/to/photo.jpg"

Confirm Hazard

Community verification endpoint. Increments the confirmed_count of a hazard report. Higher confirmation counts give the hazard more weight in the safety score algorithm.

POST
/hazards/{hazard_id}/confirm
Increments confirmed_count for the given hazard by 1.
Path Parameters
ParameterTypeRequiredDescription
hazard_id string (UUID) required The UUID of the hazard to confirm.
Important: Pass hazard_id as a path parameter in the URL — not in a JSON body. E.g. POST /hazards/abc-123/confirm
200 Response
JSON
{
  "message": "Hazard confirmed!",
  "confirmed_count": 4
}
Example Request
cURL
curl -X POST https://safewalk-95z8.onrender.com/hazards/abc-1234-uuid/confirm

🌟 Safety Score

Get a calculated safety score (0–100) for any location. The algorithm weighs nearby hazards by type severity, recency, time of day, and community confirmations.

GET
/safety-score
Returns a 0–100 safety score and human-readable label for a coordinate.
Query Parameters
ParameterTypeRequiredDescription
latitude float required Latitude of the location to score.
longitude float required Longitude of the location to score.
radius float optional Search radius in degrees. Default: 0.01 (~1 km). Always use degree values, not kilometres.
200 Response
JSON
{
  "latitude": 13.0827,
  "longitude": 80.2707,
  "nearby_hazards_count": 3,
  "safety_score": 72.5,
  "safety_label": "⚠️ Use Caution"
}
Example Request
cURL
curl "https://safewalk-95z8.onrender.com/safety-score?latitude=13.0827&longitude=80.2707&radius=0.01"

🔐 Authentication

User registration and login endpoints. Login returns a JWT token for authenticated requests.

POST
/auth/register
Create a new user account.
Request Body (JSON)
FieldTypeRequiredDescription
username string required Display name for the user.
email string required Unique email address.
password string required Password (hashed with bcrypt before storage).
200 Response
JSON
{
  "message": "Registration successful!",
  "user": {
    "username": "vishaal",
    "email": "vishaal@example.com"
  }
}
POST
/auth/login
Authenticate a user and receive a JWT token.
Request Body (JSON)
FieldTypeRequiredDescription
email string required Registered email address.
password string required Account password.
200 Response
JSON
{
  "message": "Login successful!",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "username": "vishaal"
}
Example Request
cURL
curl -X POST https://safewalk-95z8.onrender.com/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"vishaal@example.com","password":"yourpassword"}'

🏷 Hazard Types

Valid values for the type field when reporting hazards.

manholeOpen Manhole
floodingFlooding / Waterlogging
no_lightNo Streetlight
broken_footpathBroken Footpath
unsafe_areaUnsafe Area
no_wheelchair_accessNo Wheelchair Access

🧮 Scoring Algorithm

How the /safety-score endpoint calculates a score. Each nearby hazard contributes a danger value; the score is max(0, 100 − total_danger).

Hazard Severity Weights
Hazard TypeBase WeightNotes
manhole10Highest — immediate physical danger
flooding9Impassable and injury risk
unsafe_area8Security concern
no_light7+50% multiplier applied at night (8 PM–6 AM)
no_wheelchair_access6Accessibility barrier
broken_footpath5Moderate — trip hazard
Recency Factors
Age of ReportMultiplier
Under 24 hours1.0 (full weight)
1–3 days0.7
3–7 days0.4
Older than 7 days0.1
Safety Score Labels
Score RangeLabel
80 – 100✅ Safe
60 – 79⚠️ Use Caution
40 – 59🟠 Moderate Risk
0 – 39🔴 High Risk

⚠️ Error Codes

All errors return a JSON body with a detail field describing what went wrong.

StatusMeaningCommon Cause
400 Bad Request Invalid image file, missing required fields, or email already registered.
401 Unauthorized Wrong email or password during login.
404 Not Found Hazard ID does not exist in the database.
500 Internal Server Error Supabase connection issue, missing env vars, or unexpected exception.
Error Response Shape
JSON
{
  "detail": "Hazard not found"
}