Ownware
Home›Cyresora›API
Cyresora · API

Cyresora API, as shipped in the download

Cyresora API

Every running deadline over HTTP, plus an MCP endpoint for agents. The machine-readable spec lives at /api/openapi.json.

Authentication

Mint a key in Settings -> API & agents. Every request carries it as a bearer token:

curl https://cyresora.example.com/api/deadlines \
  -H "Authorization: Bearer apk_xxxx"

Keys are scoped. Read-only or full, chosen when you mint it. A read-only key is refused any non-GET at the door, once, rather than in each route.

The one rule of this API

You cannot set a deadline. There is no due field anywhere, deliberately. You record two facts — when you became aware and when you actually submitted — and the instrument decides the rest. The one-month final-report clocks run from the submission instant, and the CRA's 14-day final report does not start at all until a corrective measure exists.

All times are UTC to the second. A 24-hour deadline cannot survive a timezone left implicit.

Endpoints

GET /api/pingVerify the key
GET /api/deadlinesEvery running deadline, worst first, hours remaining as a number
GET /api/incidentsThe register with every regime ladder. `?state=overdue\due_soon\open\pending`
POST /api/incidentsOpen an incident; the clocks start from aware_at_utc
GET /api/incidents/{id}One incident with its ladders and everything sent
POST /api/incidents/{id}/notificationsRecord a notification you have sent
GET /api/vulnerabilitiesThe vulnerability register, actively exploited first
GET /api/openapi.jsonThe spec

The endpoint a monitoring system polls

curl https://cyresora.example.com/api/deadlines -H "Authorization: Bearer apk_xxxx"
{
  "now_utc": "2026-09-14 18:00:00",
  "deadlines": [
    { "reference": "INC-20260914-A1B2", "regime": "cra_incident",
      "stage": "early", "label": "Early warning", "provision": "Article 14(3)",
      "due_utc": "2026-09-15 08:00:00", "hours_left": 14, "state": "open",
      "counted_from": "becoming aware", "deadline_at_weekend": false }
  ]
}

hours_left is signed: negative means the deadline has passed. state is one of overdue, due_soon, open or pending — and pending means the clock has not started, with counted_from naming the event that will start it.

Open an incident

curl -X POST https://cyresora.example.com/api/incidents \
  -H "Authorization: Bearer apk_xxxx" -H "Content-Type: application/json" \
  -d '{"title":"Exploited auth bypass in the gateway",
       "aware_at_utc":"2026-09-14 08:00:00",
       "regimes":["cra_incident","nis2"],
       "severity":"critical","malicious_suspected":true,"cross_border":true}'

A date with no time is refused — a 24-hour deadline cannot be computed from one. An incident with no regime is refused, because it would have no clock.

Record a notification

curl -X POST https://cyresora.example.com/api/incidents/1/notifications \
  -H "Authorization: Bearer apk_xxxx" -H "Content-Type: application/json" \
  -d '{"regime":"nis2","stage":"notify","submitted_at_utc":"2026-09-16 00:00:00",
       "recipient":"BSI","channel":"Portal","reference":"BSI-INC-88213"}'

Needs notify.submit. Refused with 422 if the stage is unknown, the regime is not running on that incident, or the time is before awareness or in the future; 409 if that stage is already recorded — a duplicate is not a second duty discharged.

Webhooks

incident.opened, notification.recorded and deadline.alert, HMAC-signed with X-Cyresora-Signature: sha256=... over the raw body. notification.recorded fires however the filing was recorded — browser, REST or agent. deadline.alert fires at each of the owner's alert points before a reporting deadline, and once when it passes, with incident, regime, stage, due_utc, hours_left, alert_point_hours and overdue.

Connect it to an assistant

Mint the key in the app first: Settings → API & agents. Choose Read only when the assistant should answer questions but never change anything — the endpoint then lists only the read tools and refuses the rest by name, so a careless prompt cannot write. Full access behaves as before.

Every client needs the same three facts, and nothing in the handshake is vendor-specific:

The addresshttps://cyresora.example.com/mcp
The keyheader Authorization: Bearer apk_xxxx
The transportMCP over streamable HTTP, stateless

Claude — one command, or the same URL and header as a custom connector in the desktop and web apps:

claude mcp add --transport http cyresora https://cyresora.example.com/mcp \
  --header "Authorization: Bearer apk_xxxx"

ChatGPT and the OpenAI API — one entry in the Responses API's tools array (in ChatGPT itself, the same URL and key go in as a connector):

{
  "type": "mcp",
  "server_label": "cyresora",
  "server_url": "https://cyresora.example.com/mcp",
  "authorization": "apk_xxxx",
  "require_approval": "never"
}

Own Your AI reads a list of servers in this shape:

{
  "mcpServers": [
    { "id": "cyresora", "name": "Cyresora", "url": "https://cyresora.example.com/mcp",
      "token": "apk_xxxx", "enabled": true }
  ]
}

**Every other client spells the same three facts differently — copy the shape from its own documentation, not from here.** VS Code is the clearest example of why: its configuration reference (read 6 September 2026) puts servers in .vscode/mcp.json under a "servers" object — *"an object that maps server names to their configurations"* — not an mcpServers array. Pasted as-is, the block above will not load there. The id, the URL and the token are what travel; the JSON around them belongs to whichever client you are configuring.

A local model, n8n, or your own code — n8n's MCP Client node takes the URL and the same Authorization: Bearer header; a model running on your own machine reaches it through any MCP client, so nothing leaves your network at all. Writing it yourself is one POST of JSON-RPC 2.0:

curl -X POST https://cyresora.example.com/mcp \
  -H "Authorization: Bearer apk_xxxx" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Any client that speaks MCP's streamable-HTTP transport works, including ones that do not exist yet: Cyresora implements the protocol, not an integration with a particular vendor.

Tools

toolaccesswhat it does
deadlinesreadEvery running clock, worst first, with hours remaining and what each is counted from. Start here.
list_incidentsreadThe register with every regime ladder
get_incidentreadOne incident in full, with everything recorded against it
what_appliesreadEach regime's stages, limits, anchors and application date — so an agent explains the duty without guessing
open_incidentwriteOpen an incident; the clocks start from the awareness time you give
record_notificationwriteRecord a notification already sent

Read tools are declared readOnly, so a read-only key does not see the write tools in tools/list and is refused them by name on tools/call.

What the agent is told, in the endpoint's own instructions: it cannot set a deadline; it must never record a notification as sent unless the human has said it was sent; it should say plainly when a deadline falls at a weekend, because the clocks do not pause; and NIS2's binding deadlines are the Member State's, which this register does not model.

← Back to Cyresora · Manual · Quickstart · Test run

Affiliate program
Recommend tools people own — earn 35% on every sale. 90-day tracking, instant delivery, payouts by Lemon Squeezy.
Become an affiliate →