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.███████████████/v1

The production base URL is not yet finalised. For early access enquiries, please email hello@communitywolf.com

Endpoints Overview

MethodEndpointDescription
POST/predictSingle location prediction
POST/predict/batchMultiple locations in one request
POST/route/riskRoute risk analysis with waypoints
GET/citiesList all available cities
GET/coverageCoverage bounds and metadata
GET/classesCrime category definitions
GET/prediction/rangeAvailable prediction date range
GET/healthService 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

FieldTypeRequiredDescription
latitudefloatYesLatitude coordinate (WGS84)
longitudefloatYesLongitude coordinate (WGS84)
datetimestringNoISO 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 LevelNO_CRIME ProbabilityInterpretation
LOW> 50%Low likelihood of crime
MODERATE25% - 50%Moderate risk
HIGH10% - 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

FieldTypeRequiredDescription
locationsarrayYesArray of location objects with latitude and longitude
datetimestringNoISO 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

FieldTypeRequiredDescription
waypointsarrayYesOrdered array of waypoint coordinates (minimum 2)
datetimestringNoISO 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

CodeHTTP StatusDescription
LOCATION_NOT_COVERED404Coordinates are outside coverage area
DATE_OUT_OF_RANGE400Requested date not available for predictions
INVALID_COORDINATES400Coordinates are malformed or out of bounds
INVALID_REQUEST400Request body is malformed
UNAUTHORIZED401Missing or invalid API key
RATE_LIMITED429Too many requests
INTERNAL_ERROR500Server 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"
  }
}