Help centre

Public API reference

The /v1 API: one header, six endpoints, JSON in and out.

Version 1.0 — 9 September 2026

Version 1.0 — 9 September 2026

The public API lets your own systems — a records system, a control-room dashboard, a toll or parking back-office — read what Suraag has already found in your footage and submit new footage for analysis. It is a small, deliberately read-heavy API: six endpoints, one header, JSON in and out.

Base URL: https://suraag.xyz/api/v1 (a dedicated or on-premises deployment has its own host; the path is the same).

1. Authentication

Every request carries an API key in the X-Api-Key header:

X-Api-Key: vf_<your key>
ScopeGrants
plate:readGET /search/plate
attrs:readGET /search/attributes
finding:readGET /finding/{id}, GET /finding/{id}/crop
ingestPOST /jobs, GET /jobs/{id}

Every call is written to your organisation's audit trail (actor apikey:<org>, the action, the target and the caller's IP), the same trail the console shows under Audit.

2. Endpoints

2.1 GET /search/plate — plate timeline

Returns every trustworthy sighting of a number plate across your cameras, newest first. Only reads at or above the platform's plate-confidence threshold are returned; low- confidence garbage reads are never surfaced.

Query parameterTypeDefaultMeaning
platestringrequiredPlate text. Case-insensitive; upper-cased before matching.
fuzzybooltruetrue = partial match (substring), false = exact match.
limitint 1–20050Maximum results.
curl -s "https://suraag.xyz/api/v1/search/plate?plate=TS09&fuzzy=true&limit=20" \
  -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx"
{
  "plate": "TS09",
  "count": 2,
  "results": [
    {
      "finding_id": "f_01J…",
      "plate": "TS09EA1234",
      "confidence": 0.93,
      "camera_id": "cam_junction_north",
      "ts_start": 412.8,
      "wall_start": "2026-09-08T18:42:11+05:30",
      "crop_url": "/api/v1/finding/f_01J…/crop"
    }
  ]
}

ts_start is seconds from the start of the analysed file; wall_start is the wall-clock time if the footage carried one (DVR export time or the edge agent's recording time), otherwise null.

Finds objects by class and attributes. All parameters are AND-combined. Attribute names and values are the ones the console's catalogue exposes (helmet, color, vehicle_type, …); gated attributes such as weapon_candidate are excluded from API results unless your key has been extended by support.

Query parameterTypeMeaning
camera_idstringRestrict to one camera.
object_kindstringperson, vehicle, object, …
clsstringDetector class, e.g. motorcycle, car, auto_rickshaw.
attrsJSON stringAttribute filter, e.g. {"color":"red","helmet":"no"}.
time_from, time_toISO-8601 datetimeWall-clock window.
limitint 1–200Default 50.
curl -s -G "https://suraag.xyz/api/v1/search/attributes" \
  --data-urlencode 'cls=motorcycle' \
  --data-urlencode 'attrs={"helmet":"no"}' \
  --data-urlencode 'time_from=2026-09-08T00:00:00+05:30' \
  -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx"

Each result carries finding_id, camera_id, cls, object_kind, ts_start, wall_start, conf, attributes (the full attribute dictionary), a one-line caption with caption_source (vlm when a vision-language model wrote it, auto when it is a template), and crop_url (or null if no crop was stored).

A malformed attrs value returns 400 attrs must be a valid JSON object.

2.3 GET /finding/{finding_id} — finding detail

Everything Suraag holds about one detection: bounding box, timing, confidence, attributes, caption, and the plate read if there is one.

curl -s "https://suraag.xyz/api/v1/finding/f_01J…" -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx"
{
  "finding_id": "f_01J…",
  "camera_id": "cam_junction_north",
  "job_id": "6c1f…",
  "cls": "motorcycle",
  "object_kind": "vehicle",
  "ts_start": 412.8, "ts_end": 416.1,
  "wall_start": "2026-09-08T18:42:11+05:30",
  "bbox": [0.41, 0.22, 0.58, 0.61],
  "conf": 0.88,
  "attributes": {"helmet": "no", "riders": "2", "color": "black"},
  "caption": "A black motorcycle with two riders, no helmet",
  "caption_source": "auto",
  "plate": {"text": "TS09EA1234", "confidence": 0.93, "present": true},
  "crop_url": "/api/v1/finding/f_01J…/crop"
}

Unknown ids, and ids that belong to another organisation, return 404 finding not found.

2.4 GET /finding/{finding_id}/crop — evidence crop

Returns the stored JPEG crop for a finding as raw bytes (Content-Type: image/jpeg).

curl -s "https://suraag.xyz/api/v1/finding/f_01J…/crop" \
  -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx" -o crop.jpg

404 crop not found when the finding has no stored crop; 502 crop unavailable in object storage if the object store cannot serve it right now — retry later.

2.5 POST /jobs — submit footage for analysis

Queues a video that is already reachable by the Suraag worker (a server-side path or an object-storage key agreed with support at onboarding — the API does not accept a video body; use the console or the edge agent to upload files). Returns 202 Accepted.

curl -s -X POST "https://suraag.xyz/api/v1/jobs" \
  -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx" -H "Content-Type: application/json" \
  -d '{"camera_id":"cam_junction_north","video_path":"ingest/2026-09-08/north.mp4","fps":2}'
Body fieldTypeMeaning
camera_idstring, requiredThe camera the footage belongs to (must be yours).
video_pathstring, requiredServer path or object-storage key of the file.
fpsnumber, optionalSampling rate for analysis (default: platform profile).
max_secondsnumber, optionalAnalyse only the first N seconds.
{"queued": true, "job_id": "arq:…", "status_url": "/api/v1/jobs/arq:…"}

2.6 GET /jobs/{job_id} — job status

curl -s "https://suraag.xyz/api/v1/jobs/arq:…" -H "X-Api-Key: vf_xxxxxxxxxxxxxxxx"
{
  "job_id": "6c1f…", "camera_id": "cam_junction_north",
  "status": "running", "progress": 0.42,
  "frames_total": 3000, "frames_done": 1260, "findings_count": 187,
  "error": null,
  "created_at": "2026-09-08T18:50:02+05:30", "updated_at": "2026-09-08T18:52:40+05:30"
}

status is one of queued, running, done, error. While the GPU analysis engine is offline, jobs stay queued and are processed when it starts — nothing is lost.

3. Errors

Errors are JSON: {"detail": "<message>"}.

CodeMeaning
400A parameter could not be parsed (for example attrs is not valid JSON).
401Missing, unknown or revoked API key.
403The key is valid but lacks the required scope.
404The finding, crop or job does not exist — or is not yours.
422Request body failed validation (missing camera_id, wrong type).
429Rate limit exceeded — back off and retry after the Retry-After header if present.
502Object storage could not serve the crop; retry.

4. Rate limits and good behaviour

5. Changes

DateChange
2026-09-09First published reference (v1).