API access and conventions

Start here for request formats, authentication, response handling and the conventions used across the API.

Choose the right API

These routes power the Rizicon web application. Public endpoints expose crossing data and historical trends, and accept private contact inquiries. Team and AI endpoints are internal beta interfaces for the signed-in application; their payloads can change as the product evolves.

Use the origin of your own deployment as the base URL, followed by the endpoint path. Before a production integration or scheduled bulk transfer, agree with Rizicon on the supported contract, scope and expected load.

API familyAccessUse it for
Public dataNo account requiredCrossing records and score history.
Contact submissionsPublic · origin checkedPrivate inquiries about demos, hosting or partnerships.
Team analysis and AIanalyst · admin · rizicon_adminAuthorised analysis and optional AI features.
Contact managementrizicon_adminRead, triage and delete contact inquiries.

Examples use synthetic records and placeholder city slugs. They illustrate the documented shape, not live results. Examples labelled “selected fields” omit other properties returned by the endpoint.

Make your first request

Read endpoints use GET with URL query parameters. Mutation endpoints use the method shown on their reference card. For JSON request bodies, send Content-Type: application/json. Keep field names and enum values exactly as documented; locale changes human-facing content, not property names.

Request and response examples

Request · replace the base URLbash
curl --get 'https://YOUR_DEPLOYMENT/api/crosswalks' \
  --data-urlencode 'city=YOUR_CITY_SLUG' \
  --header 'Accept: application/json'
Browser request · check HTTP and application errorsjavascript
const query = new URLSearchParams({ city: 'YOUR_CITY_SLUG' })
const response = await fetch('/api/crosswalks?' + query)
const result = await response.json()

if (!response.ok || result.error) {
  throw new Error(result.error ?? 'Request failed: ' + response.status)
}

console.log(result.crosswalks)

Authentication and permissions

Protected routes use the Supabase session stored in request cookies. Sign in through the application and make requests from the same origin. The server validates the session and reads current role and city permissions from the database.

A Supabase publishable key alone does not grant team access. The browser examples reuse the signed-in session; they do not require copying a token into source code. Keep service-role keys and AI provider secrets out of public code.

Request and response examples

Authenticated request · run while signed injavascript
const response = await fetch(
  '/api/manage-analysis?kind=cities&page=1&pageSize=25',
  { credentials: 'same-origin', cache: 'no-store' },
)
const result = await response.json()
if (!response.ok) throw new Error(result.error ?? 'Request failed')
console.log(result.items, result.total, result.summary)

Read status codes and response bodies

Response envelopes are specific to each endpoint. Data endpoints return an array and an error field; successful contact mutations return ok. Check the reference for the exact shape instead of assuming every route has a data property.

StatusHow to handle it
200 / 201Read the body. Some AI routes return an error even with HTTP 200. Contact creation normally returns 201.
400Correct the request fields or JSON. Contact validation includes the first invalid field.
401 / 403Check the session, role and origin. Analyst routes use 401 for both missing sessions and insufficient roles; contact management distinguishes 401 and 403.
404The requested city could not be resolved, or a managed contact record was not found.
413 / 429Reduce a contact request larger than 24,000 bytes. For rate limits, respect Retry-After before submitting again.
502 / 503Data or storage is unavailable. Surface the error and avoid tight retry loops.

AI chat uses application/x-ndjson: parse one complete JSON line at a time. A streamed error frame can arrive after HTTP 200. See the Team and AI API page for frame types and stream handling.

Filtering and pagination

Always URL-encode query values. Omit optional filters when you want their documented default. Use totals returned by paginated endpoints to decide whether another page is available.

EndpointConvention
/api/crosswalkscity is a slug. Returns matching crossings in one response; no client-facing page parameter.
/api/score-historycity is a slug or numeric ID. Returns one aggregate point per capture date; no client-facing pagination.
/api/manage-analysispage starts at 1. pageSize accepts 10, 25, 50 or 100; default 25.
/api/manage/contactspage starts at 0. Each page contains at most 20 records.
Discuss an integration