API v1 reference
The CRAnotify public API is a small, deliberate B2B surface: it registers an inbound security signal, reads the product catalogue and the compliance score, and receives bills of materials from pipelines. It always returns JSON. Every call is authenticated with an API key belonging to your organisation and is scoped to that organisation: a key never sees another customer's data, and the tenant comes from the key, never from the request body. To explore the endpoints interactively use the console at https://api.cranotify.eu/swagger, generated from the same OpenAPI 3 specification (https://api.cranotify.eu/swagger/openapi.json).
Key management. Creating keys, choosing scopes, rotation and revocation are covered in API and integration keys. This page documents the endpoint contract.
Base address
In production the API answers on the dedicated host api.<domain>. The three reads and incident intake also answer there in the short /v1 form:
https://api.cranotify.eu/v1/products
On every host (including the unified development host) the same endpoints answer under the full prefix /api/v1/external. SBOM ingest is available only in that full form. The downloaded specification reports the address of the host that served it.
Authentication
Present the key in the X-CRA-API-Key header or as a bearer token. The two are equivalent.
X-CRA-API-Key: cra_live_…
# or
Authorization: Bearer cra_live_…
Read endpoints allow only GET; incident intake and SBOM ingest accept only POST. Any other method returns 405.
Scopes
Each key carries one or more scopes; the required scope is specific to the endpoint. There are no all-purpose keys: a read-only key cannot open an incident or push an SBOM.
| Scope | Unlocks |
|---|---|
incidents:write | Register an inbound security signal. |
products:read | Read the product catalogue with SBOM status and risk level. |
compliance:read | Read the organisation's compliance score. |
products:write | Push a bill of materials from your pipelines. |
Endpoints
The public surface is four endpoints. There is no pagination: lists come back whole with their count.
| Method and path | Scope | Description |
|---|---|---|
POST /api/v1/external/incidents | incidents:write | Registers an inbound security signal (INCOMING). It does not create a case: no awareness, no 24h/72h clock. Turning it into a case is a human decision in the console. |
GET /api/v1/external/products | products:read | Product catalogue with bill-of-materials status and risk level derived from active cases. Returns {"products":[…],"count":N}. |
GET /api/v1/external/compliance-score | compliance:read | Real-time compliance KPIs: rule-based CRA Health Score, average MTTN, SBOM coverage, active 24h/72h timers. |
POST /api/v1/external/products/{sku}/sbom | products:write | Ingest a CycloneDX/SPDX SBOM for the product identified by SKU. Converges on the same release-versioned model as web and CLI uploads (see Bill of materials). |
On the dedicated host api.cranotify.eu the first three also answer in the short form /v1/incidents, /v1/products, /v1/compliance-score.
There are no endpoints for reading cases, the key profile, the registry or registry verification from the public API: those are console-only operations. The API returns no paginated envelope.
Rate limit
Each key is limited to 100 requests per minute. Over the limit the response is 429 with the headers X-RateLimit-Limit, X-RateLimit-Remaining and Retry-After.
Examples
# Product catalogue
curl -H "X-CRA-API-Key: cra_live_…" https://api.cranotify.eu/v1/products
# Compliance score
curl -H "Authorization: Bearer cra_live_…" https://api.cranotify.eu/v1/compliance-score
# Open an inbound signal
curl -X POST -H "X-CRA-API-Key: cra_live_…" -H "Content-Type: application/json" \
-d '{"title":"…","description":"…"}' \
https://api.cranotify.eu/v1/incidents
# Push an SBOM for an SKU
curl -X POST -H "X-CRA-API-Key: cra_live_…" -H "Content-Type: application/json" \
--data-binary @sbom.cyclonedx.json \
https://api.cranotify.eu/api/v1/external/products/SKU-123/sbom
What the API does not expose
The product catalogue carries metadata and compliance status, never the organisation's secrets. A reporter's identity and contact, Privilege Vault notes, TOTP secrets and attachment storage keys are not reachable from the public API.
Error codes
| Code | Meaning |
|---|---|
401 | Missing, wrong, revoked or expired key. |
403 | Valid key without the required scope. |
405 | Method not allowed on the endpoint. |
422 | Invalid body: missing fields on incident intake, or an SBOM that is neither CycloneDX nor SPDX. |
429 | Rate limit exceeded (100/min per key). |
Specification and API console
https://api.cranotify.eu/swagger page (/docs stays an alias) shows every endpoint, its parameters, schemas and examples. Self-hosted, no CDN.https://api.cranotify.eu/swagger/openapi.json — import it into Postman, Insomnia or a client generator.