Developer Reference

Civesto Authority API

The same interface the authority console uses: read the reports in your jurisdiction, record outcomes, pull aggregates, export in the formats your systems consume, and receive events by webhook. Base URL https://civesto.com/v1/kurumsal. Every response is JSON unless it is a file.

Quickstart

Three calls tell you whether the integration works: who you are, what is waiting, and one case in full.

  1. Obtain a key from your authority's IT contact (created in the console under API keys) or from [email protected] for a pilot. Keys look like civ_live_prod_… and are shown once.
  2. Call GET /me — it returns your authority, your scopes and your role.
  3. Call GET /ihbarlar?limit=20 — the newest reports in your jurisdiction — then GET /ihbarlar/{id} for one of them.
# who am I, what may I do
curl https://civesto.com/v1/kurumsal/me \
  -H "X-Civesto-Key: civ_live_prod_REPLACE_ME"

# newest reports in my jurisdiction (cursor pagination)
curl "https://civesto.com/v1/kurumsal/ihbarlar?limit=20&durum=new" \
  -H "X-Civesto-Key: civ_live_prod_REPLACE_ME"

# record an outcome (needs the case_write scope)
curl -X POST https://civesto.com/v1/kurumsal/ihbarlar/211/status \
  -H "X-Civesto-Key: civ_live_prod_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{"durum": "validated", "not": "Legal basis: SRTI Art. 3(b) — confirmed on site"}'
import requests

BASE = "https://civesto.com/v1/kurumsal"
H = {"X-Civesto-Key": "civ_live_prod_REPLACE_ME"}

me = requests.get(BASE + "/me", headers=H, timeout=10).json()
print(me["tenant"]["ad"], me["role"], me["scopes"])

page = requests.get(BASE + "/ihbarlar", headers=H, params={"limit": 20, "durum": "new"}, timeout=10).json()
for r in page["items"]:
    print(r["id"], r["referans"], r["ihlal_turu"], r["durum"], r["olusturulma_zamani"])
# page["next_cursor"] -> pass as ?cursor= for the next page
using System.Net.Http;
using System.Net.Http.Json;

var client = new HttpClient { BaseAddress = new Uri("https://civesto.com/v1/kurumsal/") };
client.DefaultRequestHeaders.Add("X-Civesto-Key", "civ_live_prod_REPLACE_ME");

var me = await client.GetFromJsonAsync<JsonElement>("me");
var page = await client.GetFromJsonAsync<JsonElement>("ihbarlar?limit=20&durum=new");
foreach (var r in page.GetProperty("items").EnumerateArray())
    Console.WriteLine($"{r.GetProperty("id")} {r.GetProperty("ihlal_turu")} {r.GetProperty("durum")}");
const BASE = "https://civesto.com/v1/kurumsal";
const H = { "X-Civesto-Key": "civ_live_prod_REPLACE_ME" };

const me = await (await fetch(`${BASE}/me`, { headers: H })).json();
const page = await (await fetch(`${BASE}/ihbarlar?limit=20&durum=new`, { headers: H })).json();
for (const r of page.items) console.log(r.id, r.referans, r.ihlal_turu, r.durum);

Authentication & roles

One header. The key identifies the authority (tenant) and carries the scopes; nothing else is needed. Keys are stored as Argon2id hashes — the plain value exists only where you keep it.

Headers

HeaderRequiredDescription
X-Civesto-KeyYesThe API key (civ_live_…). Authorization: Bearer <key> is accepted as an alternative.
Accept-LanguageNoRFC 5646 tag; validation messages follow it where a translation exists, otherwise English.
Content-TypePOST/PATCHapplication/json.

Scopes

A key carries a set of scopes. Each endpoint states what it needs; a call without it returns 403 with the missing scope named in details. A key can never create another key with more than it holds itself.

ScopeGrants
readReports in the jurisdiction: list, detail, evidence media, map data, summary.
exportFile exports (/ihbarlar/export) and CAP alerts.
case_writeRecord an outcome on a report (/ihbarlar/{id}/status).
stats_readAggregates only — summary, trend, heatmap — with no case-level record.
audit_readThe authority's own audit log.
webhook_adminCreate, test, pause and delete webhooks; read deliveries.
key_adminList, create and revoke API keys of the authority.
gov_adminTenant administration (also satisfies case_write).

Role presets

The console creates keys by role; a role is simply a scope set. The console shows only what the key can use.

RoleScopesWho
Case officerread export case_writeHandles reports, reads evidence, records outcomes, prints case files.
Management viewstats_readSees volume, outcomes, response times, hotspots and the activity report — never an individual case.
IT / systemsaudit_read webhook_admin key_adminRuns the integration: keys, webhooks, audit — never case content.

Endpoints

All paths are relative to /v1/kurumsal. Jurisdiction is enforced on every report query: a key sees only the reports of its authority's area, and an id outside it answers 404.

Method · pathScopePurpose
GET /healthLiveness.
GET /meanyTenant, key prefix, scopes, role, hourly allowance.
GET /usageanyRequests in the last hour and today against the allowance.
GET /ihbarlarreadReports, newest first. Filters: durum, suc_tipi, il, ilce, baslangic, bitis; limit ≤ 500; cursor for the next page.
GET /ihbarlar/{id}readOne report with evidence seal, forensic observations, routing decision.
GET /ihbarlar/{id}/foto?idx=0readEvidence media (image or video) — served only through the key, never by file name.
POST /ihbarlar/{id}/statuscase_writeRecord an outcome: new · validated · forwarded · acted · closed, with an optional note. Audit-logged.
GET /ihbarlar/ozetread or stats_readPeriod summary — counts, outcome mix, response times, backlog age, recurring locations, arrival pattern.
GET /ihbarlar/agregaread or stats_readCounts per hourly · daily · weekly · monthly bucket.
GET /ihbarlar/heatmapread or stats_readGrid-binned counts (anonymised); resolution 1–10, optional bbox.
POST /ihbarlar/georeadReports inside a polygon or radius.
GET /ihbarlar/export?fmt=…exportFile export — see Exports.
GET /ihbarlar/{id}/capexportCAP 1.2 alert of the routing decision (road-hazard categories).
GET /export-jobs/{id}exportStatus of an asynchronous export.
GET · POST /webhooks, GET · PATCH · DELETE /webhooks/{id}webhook_adminManage subscriptions.
POST /webhooks/{id}/test, GET /webhooks/{id}/deliverieswebhook_adminPing the endpoint; read the delivery log.
GET · POST /keys, DELETE /keys/{id}key_adminList, create (plain key returned once), revoke with a reason.
GET /auditaudit_readThe authority's audit log; filters since, until, method, status_min.
GET /openapi.jsonMachine-readable schema of everything above.

Reports

A report is what one citizen submitted, plus what the platform could verify about it. The record carries observations, not conclusions: the assessment is the authority's.

FieldMeaning
id, referansNumeric API handle; business reference printed on documents (e.g. RD-DEMO-004).
ihlal_turu, suc_tipiStable category code (e.g. yolda_engel) and its English label. Road-hazard codes carry the SRTI article, (EU) 886/2013.
durumPipeline status: new · under_review · validated · forwarded · acted · closed.
olusturulma_zamani, islem_tarihiServer receipt time; last recorded action. Device capture time is not exposed by this field.
enlem, boylam, mahalle, il, ilcePosition and address text as reported; jurisdiction keys.
plaka, plaka_hashPartially masked plate value and a pseudonymous grouping value where present. Masking is not anonymisation; uploaded media can still contain identifying details.
oncelik, ai_skorRule-based dispatch priority; ai_skor is a retained compatibility field, not a validated reliability or authenticity assessment.
medya_muhur, evidence_sealSHA-256 fingerprints taken at upload; the report's position in the Ed25519-signed, append-only chain.
forensicsWhat the file discloses about itself: capture metadata, encoding traces, Content Credentials (including a declared generative origin), measured road conditions for hazard categories. Severities info · caution · flag; no score.
dispatchProposed recipient roles, dispatch urgency and routing rationale. A queued routing entry does not prove delivery or human acknowledgement.
foto_urlPath of the protected media endpoint, or null.

Recording an outcome

POST /ihbarlar/{id}/status
{ "durum": "forwarded", "not": "Legal basis: StVO § 12 Abs. 4 — forwarded to the fine office" }

Status changes are recorded in the audit log. The receiving authority must define the processing purpose and applicable legal basis. If a webhook subscribes to report.updated, the change also queues an event.

Summary & statistics

GET /ihbarlar/ozet?days=30 (or baslangic/bitis) returns the period in aggregate: totals, outcome mix, category and priority breakdown, backlog age (open, new, waiting over 72 h, oldest), response times (median, p90, mean of submission → first action), evidence-sealed share, recurring locations (same condition within ~150 m, with open count and centroid) and a weekday × hour arrival matrix. It contains no case identifier, so a stats_read key may call it; repeat plates (masked) are added only for keys that hold read.

GET /ihbarlar/agrega?granularity=daily gives the volume trend; GET /ihbarlar/heatmap?resolution=6 gives ~700 m grid cells for a map layer. The console's Statistics and Activity report views are built from exactly these three calls.

Exports

GET /ihbarlar/export?fmt=… exports records within the key's jurisdiction. The recipient must validate the format and permitted fields; the presence of an adapter is not a completed integration.

fmtOutputTypical consumer
csvUTF-8 with BOMExcel, LibreOffice
xlsxWorkbook: summary · detail · statisticsManagement reporting
jsonArray of recordsAny system
geojsonRFC 7946 FeatureCollectionQGIS, ArcGIS, PostGIS, web maps
pdfOne page per reportFiles, prosecution bundles
pdfa3PDF/A-3 export candidate; archival validation requiredLong-term public records
xmlPlain record schemaDocument management
datex2Generic DATEX II v3.5 test publication, validated against pinned XSDs; datex2_profile=generic-3.5-test. Unsupported categories block the export. National profiles and real publication are not enabled.Acceptance testing with an agreed receiving system

CAP: GET /ihbarlar/{id}/cap renders a report's routing decision as a Common Alerting Protocol 1.2 envelope (ETSI TS 103 479 lists CAP as a mandatory NG112 interface). It is offered as an interoperable envelope on request, not as a channel any control room already consumes.

Webhooks

Subscribe an HTTPS endpoint of your case-management system and Civesto pushes events to it; your system stays the system of record. Failed deliveries are retried (1 m → 5 m → 30 m → 2 h → 6 h → 24 h) and every attempt is visible in the delivery log.

Events

EventEmitted when
report.createdA new report in the authority's jurisdiction was accepted.
report.updatedAn outcome was recorded on a report (status change with its note).
*Everything, including future event types.

Verifying a delivery

Each POST carries X-Civesto-Event, X-Civesto-Event-Id (idempotency key — deliveries may repeat), X-Civesto-Timestamp and X-Civesto-Signature: sha256=<hex>, an HMAC-SHA256 of the raw request body with the signing secret shown once at creation.

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest("sha256=" + expected, header)

Answer 2xx quickly and process asynchronously; anything else is retried. The endpoint must be a public HTTPS address — private and link-local ranges are refused at creation.

Keys & audit

POST /keys with {"isim", "scopes", "ip_allowlist", "expires_at"} returns the plain key exactly once. Give every person, integration and wall display its own key with the smallest role that does the job; revoke with DELETE /keys/{id}?reason=… the moment it is not needed. last_used_at answers "is this key still in use?".

GET /audit lists every call made with the authority's keys — timestamp, action, result, origin address, duration — and is the authority's own record of processing. The console adds a CSV export of it.

Errors & limits

Errors are JSON with a stable code, a readable message and details:

{ "error": "forbidden", "message": "This API key is not permitted to perform that action",
  "details": { "required": ["read"], "granted": ["stats_read"] } }
StatusMeaning
401Key missing, malformed, expired or revoked.
403Key lacks the scope, or the source address is outside the key's allow-list.
404Not in your jurisdiction, or it does not exist — the two are not distinguished.
409Nothing to produce (e.g. a CAP alert for a category without a routing rule).
422Validation — the message names the field.
429Hourly allowance reached; Retry-After is set.

The allowance is per key and per hour, set per agreement (plan defaults from 1,000 to 1,000,000 requests/hour); GET /usage shows consumption. List responses carry X-Civesto-Record-Count.

OpenAPI reference

The complete, generated schema is at /v1/kurumsal/openapi.json. Click Authorize below to try requests with your own key — every call you make here is audit-logged like any other.