Public API reference · 27 September 2026
Kovira API v1
Build integrations with consistent resources, clear schemas, and authenticated requests. Explore customer REST, SCIM provisioning, provider callbacks, and calendar feeds.
https://api.kovira.app/v1
01 · URL architecture
Major group before operation
Every externally consumable endpoint follows
/v1/{major-group}/{operation-or-resource}. Group names
are lowercase and case-sensitive. Canonical examples omit the
terminal slash; a single terminal slash is normalized, but nested
suffixes and duplicate separators are rejected.
/v1 ├── calendar/feeds/ opaque-token iCalendar feeds ├── cis/ configuration items ├── problems, changes, requests, customers, audit-entries ├── incidents/ incident records and transitions ├── integrations/ provider-signed callbacks ├── l2/ network observations ├── platform/health authenticated service liveness └── scim/v2/ SCIM 2.0 provisioning
/api/*, /v1.0/*, uppercase group,
check-in, endpoint-ID, or alternate-header aliases. Unknown
endpoints return a version-stamped JSON 404.
02 · Contract conventions
Predictable on the wire
Success envelope
REST resources live in data. Cursor lists also
include meta.next_cursor.
{
"data": [{ "id": "…" }],
"meta": { "next_cursor": null }
}
Error envelope
HTTP status remains authoritative. The body supplies a stable machine code and safe message.
{
"error": {
"code": "validation_failed",
"message": "Invalid input."
}
}
| Convention | Contract |
|---|---|
| Media type |
application/json; send
Content-Type on body-bearing requests.
|
| Identifiers | UUID strings unless a field explicitly says otherwise. |
| Timestamps | UTC ISO-8601 / RFC 3339 strings. |
| Pagination | Keyset cursors are opaque. Pass the returned cursor unchanged. Every customer list defaults to 25 rows and allows at most 100. Pages include next_cursor, has_more and total_count (null when unavailable). |
| Unknown input | Mutation bodies and query parameters are strict; extra fields and repeated query parameters are rejected. JSON bodies must be UTF-8 application/json objects, capped at 1 MiB. Names and titles are trimmed before checking length. |
| Correlation |
Send a UUID in X-Request-ID. Kovira echoes valid
IDs or generates one.
|
| Version |
Every API response carries Kovira-API-Version: 1.
|
Customer API authentication
Every customer REST read, write and retry requires an explicit
active or trialing workspace subscription and an enabled license
plan. Paid licenses and trials must have an unexpired billing
period. Explicit active free licenses are accepted. Missing,
inactive or expired licensing returns
403 license_required. Keys must be unexpired and
unrevoked, and their issuer must remain an active tenant member.
Licensing storage failures return 503 and deny access.
Create a tenant-bound key in Workspace Settings → API Keys. Send it on REST calls. Keys are hashed at rest, individually scoped, expirable, and revocable.
Authorization: Bearer kvr_live_REDACTED
03 · Failure semantics
Errors, limits, and retries
| Status | Typical code | Meaning |
|---|---|---|
| 400 |
invalid_query, validation_failed
|
Path, cursor, JSON, or fields are invalid. |
| 401 | unauthorized |
Credentials are missing or invalid. Key state is deliberately not disclosed. |
| 403 | insufficient_scope |
Authentication succeeded but the principal cannot perform the operation. |
| 404 | not_found |
The endpoint or tenant-scoped resource does not exist. |
| 409 |
invalid_transition,
read_only_resource
|
The requested state conflicts with the resource contract. |
| 413 | payload_too_large |
Customer request bodies exceed 1 MiB. |
| 429 | rate_limited |
Wait for Retry-After; use exponential backoff
with jitter.
|
| 503 | dependency_unavailable |
A safety dependency failed closed. Retry only idempotent work. |
Customer keys receive 60 requests per rolling minute. Responses
expose X-RateLimit-Limit,
X-RateLimit-Remaining, and
X-RateLimit-Reset. A separate pre-authentication IP
limit bounds credential spraying.
04 · System API
Platform
A lightweight liveness resource for load balancers and external monitors. It checks request handling, not downstream dependency health; operational history remains on the public status page.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | /v1/platform/health | Bearer API key | Return process liveness, API major, and check time. |
05 · Customer REST
Incidents
Incident fields and lifecycle transitions are separate. Use the transition resource for status changes; PATCH handles descriptive and assignment fields.
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /v1/incidents | incidents:read |
List. Filters: status, priority; max
100.
|
| POST | /v1/incidents | incidents:write | Create an incident. |
| GET | /v1/incidents/{id} | incidents:read | Fetch one tenant-scoped incident. |
| PATCH | /v1/incidents/{id} | incidents:write | Update non-lifecycle fields. |
| POST | /v1/incidents/{id}/transitions | incidents:write | Apply the server-enforced state machine. |
Enums. Status: new,
assigned, in_progress, resolved,
closed. Priority: p1–p4.
Impact and urgency: high, medium,
low.
Resolution records restored service and stops SLA timing. Administrative closure records confirmation. Once an incident has been declared major, major_review_required retains its structured review obligation even if the current classification changes. Reopening requires a reason and preserves the original SLA deadlines and breach history.
Use record_response: true when starting work to record the first human response. Assignment and automated dispatch do not record a response. The server stamps the response time and responding identity once, preserving any response breach.
06 · Customer REST
Configuration items
The CMDB list is a unified projection across CI tables. Writes
expose a deliberately narrow base shape: type,
name, description, status,
and customer_id.
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /v1/cis | cis:read |
List. Filters: canonical type and
status; max 100.
|
| POST | /v1/cis | cis:write | Create a writable CI type; plan limits fail closed. |
| GET | /v1/cis/{id} | cis:read | Return the safe public projection; secret and internal columns are excluded. |
| PATCH | /v1/cis/{id} | cis:write | Version-snapshot, update, audit, and emit a webhook. |
Writable types. device,
network, service, rack,
domain, document, vendor,
location, contract, person,
group, api, license,
software, wan, sla,
saas_app, business_service,
quote.
Incident/change projections, password records, and integration-managed Entra/Intune records are readable where present but cannot be mutated through generic CI routes.
Generic CI writes support the 18 types listed in OpenAPI. Quotes and other workflow-specific records remain readable through this API; their lifecycle is managed through the corresponding domain workflow.
07 · Customer REST
Layer 2 observations
Read-only operational data produced by VECTOR’s signed ingest pipeline. The public key never receives write access to observation tables.
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /v1/l2/transceivers | l2:read | Inventory plus the latest lane-0 digital diagnostics. Max 100. |
| GET | /v1/l2/anomalies | l2:read | Open or historical anomalies, filtered by severity, type, or CI. Max 100. |
| GET | /v1/l2/cdp | l2:read | CDP neighbour observations by local switch or neighbour ID. Max 100. |
08 · REST records and audit
Core records and catalog
Incidents, configuration items, problems, changes, requests and customers support GET, POST and PATCH. Each endpoint requires a tenant-bound bearer key with the matching resource scope and an active workspace license. Request type discovery uses requests:read. Audit entries are read-only.
Lists use limit and cursor with data and meta.next_cursor, meta.has_more and meta.total_count. Search matches the title or name. updated_after selects records changed after an RFC 3339 timestamp. Record lists accept customer_id and assignee_id where applicable; use null for unassigned. Keep filters unchanged while following cursors.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/problems | List problems |
| POST | /v1/problems | Create Problem |
| GET | /v1/problems/{id} | Get problems |
| PATCH | /v1/problems/{id} | Update Problem |
| GET | /v1/changes | List changes |
| POST | /v1/changes | Create Change |
| GET | /v1/changes/{id} | Get changes |
| PATCH | /v1/changes/{id} | Update Change |
| GET | /v1/requests | List requests |
| POST | /v1/requests | Create ServiceRequest |
| GET | /v1/requests/{id} | Get requests |
| PATCH | /v1/requests/{id} | Update ServiceRequest |
| GET | /v1/customers | List customers |
| POST | /v1/customers | Create Customer |
| GET | /v1/customers/{id} | Get customers |
| PATCH | /v1/customers/{id} | Update Customer |
| GET | /v1/audit-entries | List audit-entries |
| GET | /v1/incidents/{id}/comments | List IncidentComment |
| POST | /v1/incidents/{id}/comments | Create IncidentComment |
| POST | /v1/problems/{id}/transitions | Transition Problem |
| POST | /v1/changes/{id}/transitions | Transition Change |
| POST | /v1/requests/{id}/transitions | Transition ServiceRequest |
| GET | /v1/incidents/{id}/comments/{commentId} | Get IncidentComment |
| GET | /v1/problems/{id}/comments | List ProblemComment |
| POST | /v1/problems/{id}/comments | Create ProblemComment |
| GET | /v1/problems/{id}/comments/{commentId} | Get ProblemComment |
| GET | /v1/requests/{id}/comments | List RequestComment |
| POST | /v1/requests/{id}/comments | Create RequestComment |
| GET | /v1/requests/{id}/comments/{commentId} | Get RequestComment |
| GET | /v1/request-types | List RequestType |
| GET | /v1/request-types/{id} | Get RequestType |
| GET | /v1/request-types/{id}/fields | List RequestField |
POST to a transitions collection applies the record lifecycle. Approvals, resolution evidence, and blackout restrictions remain enforced. Customer status can be set to archived and restored to active through PATCH. Closed records cannot be edited. Request creation requires an enabled catalog type and validated form_data; approvals are recorded through the approval workflow.
GET details and successful record writes return ETag.
Supply it as If-Match for every PATCH or lifecycle
transition. Missing headers return 428; stale revisions and racing
writes return 412. Fetch the latest record before attempting a new
mutation.
Use Idempotency-Key on writes. Completed retries retain
status, body, Location and ETag for 24 hours. Reuse the original
input and If-Match value. Changed input or If-Match, concurrent
requests and uncertain outcomes return 409. Authentication and
licensing are checked again before a replay.
Comment collections support POST, paginated GET and detail GET. HTML is sanitized. Private notes require the key issuer to have the matching update permission; otherwise they are omitted from lists and return 404 on detail reads. Request catalog field collections return a bounded array of at most 50 definitions.
GET /v1/problems?limit=25&status=analyzing&customer_id=null
PATCH /v1/problems/{id}
Authorization: Bearer kvr_live_REDACTED
Content-Type: application/json
If-Match: "ETAG_FROM_GET"
Idempotency-Key: problem-update-1
{"root_cause":"Configuration error"}
09 · Identity provisioning
SCIM 2.0
Use the dedicated SCIM bearer issued by Kovira. SCIM resource media types and error shapes follow RFC 7644. The product major and SCIM protocol major remain visibly separated in the path.
| Methods | Path | Purpose |
|---|---|---|
| GET | /v1/scim/v2/ServiceProviderConfig | Supported SCIM features. |
| GET | /v1/scim/v2/ResourceTypes | Resource type discovery. |
| GET | /v1/scim/v2/Schemas | Schema discovery. |
| GET POST | /v1/scim/v2/Users | List/filter or provision users. |
| GET PUT PATCH DELETE | /v1/scim/v2/Users/{id} | Read, replace, modify, or deactivate a user. |
| GET POST | /v1/scim/v2/Groups | List/filter or provision groups. |
| GET PUT PATCH DELETE | /v1/scim/v2/Groups/{id} | Read, replace, modify, or remove a group. |
12 · Provider callbacks
Integrations
These are provider-to-Kovira callbacks. Authentication is provider-specific: Stripe signature, Slack signing secret, or Microsoft Bot Framework identity. Public API bearer keys are not accepted.
| Method | Path | Caller |
|---|---|---|
| POST | /v1/integrations/stripe/webhook | Stripe webhook delivery. |
| POST | /v1/integrations/slack/commands | Slack slash commands. |
| POST | /v1/integrations/slack/interactions | Slack interactive payloads. |
| POST | /v1/integrations/teams/activities | Microsoft Teams bot activities. |
13 · Token feeds
Calendar feeds
| Method | Path | Media type | Authentication |
|---|---|---|---|
| GET | /v1/calendar/feeds/{token} | text/calendar |
The high-entropy token is the credential. |
Do not put feed URLs in logs, analytics, support screenshots, or public documents. Rotate a feed token when it may have been disclosed.
Explore the contract
Interactive API reference
Search every public operation, inspect request and response schemas, and build requests with examples. Credentials stay in memory for this tab.
14 · Working examples
Start with discovery
curl --fail-with-body -H 'Authorization: Bearer kvr_live_REDACTED' https://api.kovira.app/v1
List open high-priority incidents
curl --fail-with-body \ -H 'Authorization: Bearer kvr_live_REDACTED' \ 'https://api.kovira.app/v1/incidents?status=in_progress&priority=p1&limit=25'
Create an incident
curl --fail-with-body -X POST \
-H 'Authorization: Bearer kvr_live_REDACTED' \
-H 'Content-Type: application/json' \
--data '{"title":"Core switch unreachable","impact":"high","urgency":"high","source":"monitoring"}' \
https://api.kovira.app/v1/incidents
Continue a cursor page
curl --get \ -H 'Authorization: Bearer kvr_live_REDACTED' \ --data-urlencode 'cursor=RETURNED_OPAQUE_CURSOR' \ https://api.kovira.app/v1/cis
For SDK generation, use the complete public contract at
https://api.kovira.app/docs/openapi.yaml.
15 · Lifecycle
Versioning policy
| Change | v1 treatment |
|---|---|
| Add an optional response field or new endpoint | May ship within v1. |
| Add a new optional enum filter value | May ship within v1 when existing requests remain valid. |
| Remove or rename a field/path; change field meaning or auth |
Requires a new major group root such as /v2.
|
| Security removal before production | Removed outright. No alias is retained in this pre-production contract. |
The path major is the compatibility boundary. Additive fields may appear within v1; clients should ignore unknown response fields. Breaking public changes use a new major version.
16 · Integration checklist
Before enabling production traffic
-
Pin the base origin to
https://api.kovira.app/v1; do not derive internal/apipaths. - Grant the smallest required scopes and store keys in a secrets manager.
-
Set connection and response deadlines; retry
429and transient5xxwith jitter. -
Only retry mutations when the operation is idempotent or carries a
REST
Idempotency-Keyheader. -
Log
X-Request-ID, status, and stable error code—never credentials or calendar tokens. -
Treat cursors as opaque and validate
Kovira-API-Versionin integration tests.