Endpoints
Safety Intelligence API endpoint reference with request and response examples.
This page documents the available endpoints in the Safety Intelligence API (SIA). All endpoints return JSON responses with consistent error handling.
SIA is in internal beta. Endpoints, response formats, and data structures may change as the platform evolves.
Base URL
https://api.███████████████/v1The production base URL is not yet finalised. For early access enquiries, please email hello@communitywolf.com
Endpoints Overview
| Method | Endpoint | Description |
|---|---|---|
| POST | /predict | Single location prediction |
| POST | /predict/batch | Multiple locations in one request |
| POST | /route/risk | Route risk analysis with waypoints |
| GET | /cities | List all available cities |
| GET | /coverage | Coverage bounds and metadata |
| GET | /classes | Crime category definitions |
| GET | /prediction/range | Available prediction date range |
| GET | /health | Service health check |
POST /predict
Returns a probability distribution for crime types at a specific location and time.
Request
curl -X POST "https://api.███████████████/v1/predict" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"latitude": -26.2041,
"longitude": 28.0473,
"datetime": "2026-02-15T14:30:00"
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
latitude | float | Yes | Latitude coordinate (WGS84) |
longitude | float | Yes | Longitude coordinate (WGS84) |
datetime | string | No | ISO 8601 datetime for prediction (defaults to current week) |
Response
{
"status": "success",
"city": {
"code": "city_za_jhb",
"name": "Johannesburg CBD"
},
"location": {
"latitude": -26.2041,
"longitude": 28.0473,
"cell_id": "8730a5c524fffff",
"grid_center": {
"latitude": -26.204,
"longitude": 28.047
}
},
"prediction": {
"datetime": "2026-02-15T14:30:00",
"week_of": "2026-02-10",
"probabilities": {
"THEFT_BURGLARY": 0.32,
"BATTERY_ASSAULT": 0.18,
"VEHICLE_DAMAGE": 0.12,
"OTHER": 0.08,
"SERIOUS_VIOLENT": 0.02,
"NO_CRIME": 0.28
},
"dominant_type": "THEFT_BURGLARY",
"confidence": 0.32,
"risk_level": "MODERATE"
},
"model_info": {
"version": "sia_v3.2",
"mae": 0.038,
"last_updated": "2026-02-01"
}
}{
"status": "error",
"code": "LOCATION_NOT_COVERED",
"message": "No coverage available for this location",
"details": {
"latitude": -29.8587,
"longitude": 31.0218,
"suggestion": "This location is not currently covered. Use GET /cities to see available coverage areas."
}
}{
"status": "error",
"code": "INVALID_COORDINATES",
"message": "Latitude must be between -90 and 90",
"details": {
"field": "latitude",
"value": 95.5,
"valid_range": [-90, 90]
}
}Risk Levels
The risk_level field is derived from the NO_CRIME probability:
| Risk Level | NO_CRIME Probability | Interpretation |
|---|---|---|
LOW | > 50% | Low likelihood of crime |
MODERATE | 25% - 50% | Moderate risk |
HIGH | 10% - 25% | Elevated risk |
VERY_HIGH | < 10% | High likelihood of crime activity |
POST /predict/batch
Query multiple locations in a single request. Locations can span different cities.
Request
curl -X POST "https://api.███████████████/v1/predict/batch" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"locations": [
{"latitude": -26.2041, "longitude": 28.0473},
{"latitude": -33.9249, "longitude": 18.4241},
{"latitude": 41.8781, "longitude": -87.6298}
],
"datetime": "2026-02-15T14:30:00"
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
locations | array | Yes | Array of location objects with latitude and longitude |
datetime | string | No | ISO 8601 datetime for all predictions |
Response
{
"status": "success",
"timestamp": "2026-02-15T14:30:00",
"results": [
{
"index": 0,
"status": "success",
"city": "city_za_jhb",
"location": {
"latitude": -26.2041,
"longitude": 28.0473,
"cell_id": "8730a5c524fffff"
},
"prediction": {
"probabilities": {
"THEFT_BURGLARY": 0.32,
"BATTERY_ASSAULT": 0.18,
"VEHICLE_DAMAGE": 0.12,
"OTHER": 0.08,
"SERIOUS_VIOLENT": 0.02,
"NO_CRIME": 0.28
},
"dominant_type": "THEFT_BURGLARY",
"risk_level": "MODERATE"
}
},
{
"index": 1,
"status": "success",
"city": "city_za_cpt",
"location": {
"latitude": -33.9249,
"longitude": 18.4241,
"cell_id": "8748a5c524fffff"
},
"prediction": {
"probabilities": {
"THEFT_BURGLARY": 0.35,
"BATTERY_ASSAULT": 0.20,
"VEHICLE_DAMAGE": 0.16,
"OTHER": 0.09,
"SERIOUS_VIOLENT": 0.03,
"NO_CRIME": 0.17
},
"dominant_type": "THEFT_BURGLARY",
"risk_level": "HIGH"
}
},
{
"index": 2,
"status": "success",
"city": "city_us_chi",
"location": {
"latitude": 41.8781,
"longitude": -87.6298,
"cell_id": "8828308280fffff"
},
"prediction": {
"probabilities": {
"THEFT_BURGLARY": 0.29,
"BATTERY_ASSAULT": 0.24,
"VEHICLE_DAMAGE": 0.15,
"OTHER": 0.11,
"SERIOUS_VIOLENT": 0.04,
"NO_CRIME": 0.17
},
"dominant_type": "THEFT_BURGLARY",
"risk_level": "HIGH"
}
}
],
"summary": {
"total": 3,
"successful": 3,
"failed": 0
}
}POST /route/risk
Analyse risk along a route defined by waypoints. Returns segment-by-segment risk breakdown and cumulative route score.
Request
curl -X POST "https://api.███████████████/v1/route/risk" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"waypoints": [
{"latitude": -26.2041, "longitude": 28.0473},
{"latitude": -26.1463, "longitude": 28.0437},
{"latitude": -26.1076, "longitude": 28.0567}
],
"datetime": "2026-02-15T22:30:00"
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
waypoints | array | Yes | Ordered array of waypoint coordinates (minimum 2) |
datetime | string | No | ISO 8601 datetime for the journey |
Response
{
"status": "success",
"route": {
"total_waypoints": 3,
"total_segments": 2,
"total_distance_km": 12.8,
"overall_risk_score": 0.67,
"overall_risk_level": "MODERATE"
},
"segments": [
{
"segment_index": 0,
"start": {
"latitude": -26.2041,
"longitude": 28.0473,
"cell_id": "8730a5c524fffff"
},
"end": {
"latitude": -26.1463,
"longitude": 28.0437,
"cell_id": "8730a5c526fffff"
},
"distance_km": 6.5,
"risk_score": 0.58,
"risk_level": "MODERATE",
"dominant_risk": "THEFT_BURGLARY"
},
{
"segment_index": 1,
"start": {
"latitude": -26.1463,
"longitude": 28.0437,
"cell_id": "8730a5c526fffff"
},
"end": {
"latitude": -26.1076,
"longitude": 28.0567,
"cell_id": "8730a5c528fffff"
},
"distance_km": 6.3,
"risk_score": 0.74,
"risk_level": "HIGH",
"dominant_risk": "BATTERY_ASSAULT"
}
],
"recommendations": {
"highest_risk_segment": 1,
"safest_segment": 0,
"caution_areas": ["Segment 2 has elevated assault risk near Rosebank"]
}
}GET /cities
Returns all cities with available coverage and their metadata.
Request
curl "https://api.███████████████/v1/cities" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"status": "success",
"cities": [
{
"code": "city_za_jhb",
"name": "Johannesburg",
"country": "South Africa",
"timezone": "Africa/Johannesburg",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 512,
"model_mae": 0.038
},
{
"code": "city_za_cpt",
"name": "Cape Town",
"country": "South Africa",
"timezone": "Africa/Johannesburg",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 428,
"model_mae": 0.039
},
{
"code": "city_za_dbn",
"name": "Durban",
"country": "South Africa",
"timezone": "Africa/Johannesburg",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 286,
"model_mae": 0.042
},
{
"code": "city_us_chi",
"name": "Chicago",
"country": "United States",
"timezone": "America/Chicago",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 324,
"model_mae": 0.041
},
{
"code": "city_us_la",
"name": "Los Angeles",
"country": "United States",
"timezone": "America/Los_Angeles",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 412,
"model_mae": 0.043
},
{
"code": "city_us_sf",
"name": "San Francisco",
"country": "United States",
"timezone": "America/Los_Angeles",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 198,
"model_mae": 0.037
},
{
"code": "city_us_nyc",
"name": "New York City",
"country": "United States",
"timezone": "America/New_York",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 386,
"model_mae": 0.040
},
{
"code": "city_us_bos",
"name": "Boston",
"country": "United States",
"timezone": "America/New_York",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 178,
"model_mae": 0.039
},
{
"code": "city_us_phi",
"name": "Philadelphia",
"country": "United States",
"timezone": "America/New_York",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 256,
"model_mae": 0.044
},
{
"code": "city_uk_ldn",
"name": "London",
"country": "United Kingdom",
"timezone": "Europe/London",
"status": "active",
"last_updated": "2026-02-01",
"prediction_range": {
"start": "2026-01-06",
"end": "2026-10-05"
},
"grid_cells": 445,
"model_mae": 0.036
}
],
"total": 10
}GET /coverage
Returns the geographic coverage bounds for the platform or a specific city.
Request
# All cities
curl "https://api.███████████████/v1/coverage" \
-H "Authorization: Bearer YOUR_API_KEY"
# Specific city
curl "https://api.███████████████/v1/coverage?city=city_za_jhb" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"status": "success",
"city": "city_za_jhb",
"bounds": {
"north": -25.90,
"south": -26.50,
"east": 28.50,
"west": 27.70
},
"grid_cells": 512,
"cell_size_km2": 5.16,
"spatial_system": "H3",
"h3_resolution": 7
}GET /classes
Returns the standardised crime category definitions.
Request
curl "https://api.███████████████/v1/classes" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"status": "success",
"classes": [
{
"code": "THEFT_BURGLARY",
"name": "Theft & Burglary",
"description": "Property theft including burglary, robbery, and larceny",
"severity": 3
},
{
"code": "BATTERY_ASSAULT",
"name": "Assault & Battery",
"description": "Physical violence including assault, battery, and domestic incidents",
"severity": 4
},
{
"code": "VEHICLE_DAMAGE",
"name": "Vehicle & Property Damage",
"description": "Vehicle theft, vandalism, arson, and property damage",
"severity": 3
},
{
"code": "SERIOUS_VIOLENT",
"name": "Serious Violent Crime",
"description": "Homicide, sexual assault, kidnapping, and aggravated offences",
"severity": 5
},
{
"code": "OTHER",
"name": "Other",
"description": "Narcotics, weapons violations, trespass, and miscellaneous",
"severity": 2
},
{
"code": "NO_CRIME",
"name": "No Significant Crime",
"description": "Location has low crime activity for the forecast period",
"severity": 0
}
]
}GET /prediction/range
Returns the available prediction date range for a location.
Request
curl "https://api.███████████████/v1/prediction/range?latitude=-26.2041&longitude=28.0473" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"status": "success",
"location": {
"latitude": -26.2041,
"longitude": 28.0473,
"city": "city_za_jhb"
},
"range": {
"start": "2026-01-06",
"end": "2026-10-05",
"weeks_available": 43
},
"current_week": "2026-02-10"
}GET /health
Returns service health status.
Request
curl "https://api.███████████████/v1/health"Response
{
"status": "healthy",
"version": "3.2.0",
"timestamp": "2026-02-15T14:30:00Z",
"services": {
"api": "healthy",
"models": "healthy",
"database": "healthy"
}
}Error Codes
| Code | HTTP Status | Description |
|---|---|---|
LOCATION_NOT_COVERED | 404 | Coordinates are outside coverage area |
DATE_OUT_OF_RANGE | 400 | Requested date not available for predictions |
INVALID_COORDINATES | 400 | Coordinates are malformed or out of bounds |
INVALID_REQUEST | 400 | Request body is malformed |
UNAUTHORIZED | 401 | Missing or invalid API key |
RATE_LIMITED | 429 | Too many requests |
INTERNAL_ERROR | 500 | Server error |
Error Response Format
{
"status": "error",
"code": "ERROR_CODE",
"message": "Human-readable error description",
"details": {
"field": "latitude",
"value": 95.5,
"suggestion": "Latitude must be between -90 and 90"
}
}