Current v1 contract

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.

Base URL https://api.kovira.app/v1
Major versionv1
Operations66 documented calls
ContractOpenAPI 3.1

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
Strict cutover. There are no unversioned, /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.

Loading API reference…

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

  1. Pin the base origin to https://api.kovira.app/v1; do not derive internal /api paths.
  2. Grant the smallest required scopes and store keys in a secrets manager.
  3. Set connection and response deadlines; retry 429 and transient 5xx with jitter.
  4. Only retry mutations when the operation is idempotent or carries a REST Idempotency-Key header.
  5. Log X-Request-ID, status, and stable error code—never credentials or calendar tokens.
  6. Treat cursors as opaque and validate Kovira-API-Version in integration tests.