SafeWalk API
Reference
REST API powering crowdsourced pedestrian safety navigation for Indian cities. Built with FastAPI + Supabase. Deployed on Render.
📖 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).
Environment Variables
Copy .env.example to .env and fill in these values before running locally.
💚 Health Check
Verify the API server is online and responsive.
{
"status": "online",
"message": "SafeWalk Backend is active!"
}
curl https://safewalk-95z8.onrender.com/
🗺 Get Hazards
Fetch all hazards from the database. Optionally filter by geographic location using a bounding box radius.
| 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. |
{
"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
}
curl https://safewalk-95z8.onrender.com/hazards
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.
multipart/form-data, not JSON, to support optional image upload.
| 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. |
{
"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"
}
]
}
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.
| Parameter | Type | Required | Description |
|---|---|---|---|
| hazard_id | string (UUID) | required | The UUID of the hazard to confirm. |
hazard_id as a path parameter in the URL — not in a JSON body. E.g. POST /hazards/abc-123/confirm
{
"message": "Hazard confirmed!",
"confirmed_count": 4
}
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.
| Parameter | Type | Required | Description |
|---|---|---|---|
| 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. |
{
"latitude": 13.0827,
"longitude": 80.2707,
"nearby_hazards_count": 3,
"safety_score": 72.5,
"safety_label": "⚠️ Use Caution"
}
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.
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | required | Display name for the user. |
| string | required | Unique email address. | |
| password | string | required | Password (hashed with bcrypt before storage). |
{
"message": "Registration successful!",
"user": {
"username": "vishaal",
"email": "vishaal@example.com"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
| string | required | Registered email address. | |
| password | string | required | Account password. |
{
"message": "Login successful!",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "vishaal"
}
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.
🧮 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 Type | Base Weight | Notes |
|---|---|---|
| manhole | 10 | Highest — immediate physical danger |
| flooding | 9 | Impassable and injury risk |
| unsafe_area | 8 | Security concern |
| no_light | 7 | +50% multiplier applied at night (8 PM–6 AM) |
| no_wheelchair_access | 6 | Accessibility barrier |
| broken_footpath | 5 | Moderate — trip hazard |
| Age of Report | Multiplier |
|---|---|
| Under 24 hours | 1.0 (full weight) |
| 1–3 days | 0.7 |
| 3–7 days | 0.4 |
| Older than 7 days | 0.1 |
| Score Range | Label |
|---|---|
| 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.
| Status | Meaning | Common 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. |
{
"detail": "Hazard not found"
}