Getting startedAuthentication

Authentication

Authenticate every Certivant API call with a Bearer API key — covers key creation, scopes, the Authorization header format, zero-downtime rotation, revocation, and security best practices.

Every request to the Certivant API authenticates with an API key — a long-lived bearer token scoped to a single organization. Sessions and cookies are for the dashboard; the API never uses them.

Header format

Authorization: Bearer ck_live_NjV3aXJWN0RpZ2tRZ1JLWEcxc1V2eEgwUjg...
  • The header name is Authorization.
  • The scheme is Bearer (one space, then the key).
  • The key starts with ck_live_ (production) or ck_test_ (test). Older keys that start with kyk_ keep working unchanged.

Every response from a key-authenticated endpoint carries X-Certivant-Environment: live|test. Test keys only tag usage; they do not isolate data (see Live vs. test keys).

If the key is missing, unknown, revoked, expired or rotated out, Certivant responds with HTTP 401 and error.code = "UNAUTHORIZED". error.reason is a stable sub-code:

{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "reason": "api_key_expired",
    "message": "This API key has expired. Create or rotate a key."
  }
}
error.reasonHTTPMeaning
missing_api_key401No Authorization: Bearer … header.
invalid_api_key401Unknown key (typo, truncated, wrong organization).
api_key_revoked401The key was revoked.
api_key_expired401The key's expiresAt has passed.
api_key_rotated401The key was rotated and its overlap window ended — use the replacement.
insufficient_scope403The key lacks the scope this endpoint needs.
ip_not_allowed403The caller's address is not on the key's IP allowlist.
form_not_allowed403The key is restricted to other forms — see Form restriction.
workflow_not_allowed403Reserved for endpoints that take a workflow by name; the workflow restriction otherwise limits which workflows run (Workflow restriction).

Where keys come from

API keys are minted in the dashboard at KYC → Developer. You must be the organization Owner or an Admin. The key is shown only once, immediately after creation — Certivant stores a SHA-256 hash, so we cannot show it again. If you lose it, revoke and create a new one.

The dashboard lists every key (by its 8-character prefix) along with its scopes, last-used timestamp, and usage count. You can revoke a key at any time; revocation is immediate and irreversible.

Scopes

Scopes are additive. You can grant any subset when you create a key. A request to an endpoint whose required scope you don't hold returns HTTP 403 with error.code = "FORBIDDEN" and error.reason = "insufficient_scope"; the message lists every scope that would have been accepted.

Standard scopes

ScopeWhat it allows
kyc:readRead requests, list/get documents, fetch fraud signals, read KYB data, list forms, read analytics
kyc:writeCreate requests, upload documents, resubmit a rejected request, generate hosted session URLs, submit KYB entity data, send forms, schedule live verifications
kyc:submitPOST /requests/:id/submit — release a request to automated processing
kyc:manageOverride decisions on escalated requests, delete documents, delete applicants under right-to-erasure, export applicant data

Per-resource scopes

For least privilege you can grant <resource>:<action> scopes instead. Each one is accepted on the endpoints of its own resource in addition to the matching standard scope, and never reaches beyond that resource.

ResourceScopesEndpoints
verificationsread · write · submit · manage/v1/kyc/requests… (incl. KYB, EDD, fraud signals)
documentsread · write · manage/v1/kyc/requests/:id/documents…
formsread · write · manage/v1/kyc/forms…, /v1/kyc/deliveries…
live_idread · write/v1/kyc/conferences…
analyticsread/v1/kyc/analytics, /v1/kyc/summary
privacymanage/v1/kyc/deletion-requests…, /v1/kyc/applicants… (erasure, export)
webhooksread · manageWebhook endpoints — must be granted explicitly (a standard scope does not cover it)

Examples: forms:write lets a key POST /v1/kyc/forms/:formId/send but not create verification requests; verifications:read + analytics:read is a read-only dashboard key. <resource>:manage includes every other action on that resource.

The principle of least privilege applies. A frontend that only needs to display request status should hold a key with just verifications:read (or kyc:read). A backend that creates requests should hold kyc:read + kyc:write + kyc:submit. Reserve kyc:manage for internal tooling.

Restrictions

Besides scopes, a key can be restricted when you create or edit it:

  • Forms — the key may only use the forms you pick, and only reach verifications that were created through them. See Form restriction.
  • Workflows — the key may only trigger the automation workflows (by name) you pick. See Workflow restriction.
  • IP allowlist — IPv4/IPv6 addresses and CIDR ranges (203.0.113.7, 198.51.100.0/24, 2001:db8::/32). A request from any other address — or whose address cannot be determined — is refused with 403 ip_not_allowed.
  • Expiry — after expiresAt the key returns 401 api_key_expired.

All restrictions are empty (unrestricted) by default, and existing keys have none. Keys created before restrictions existed (kyk_…) and the connector's tokens are never restricted.

Form restriction

A key restricted to forms X and Y is confined to those forms and to the verifications created through them. A verification is "created through a form" when it was sent with POST /v1/kyc/forms/:formId/send (by any key or from the dashboard), submitted on the form's public link, or created with POST /v1/kyc/requests and a formId.

CallBehaviour for a form-restricted key
GET /v1/kyc/formsLists only the allowed forms.
POST /v1/kyc/forms/:formId/send, GET /v1/kyc/forms/:formId/deliveries, GET /v1/kyc/deliveries/:id403 form_not_allowed for any other form (a delivery of another form included).
POST /v1/kyc/requests and each item of /requests/batchThe formId body field names the form to create through; it must be on the list. A request without a formId, or with another form, is refused with 403 form_not_allowed (in a batch, that item fails and the others proceed). The form's own document requirements apply.
GET /v1/kyc/requestsLists only verifications created through the allowed forms.
GET /v1/kyc/requests/:id and every sub-resource (/documents, /kyb, /monitoring, /edd/start, /fraud-signals, /submit, /decision, …)403 form_not_allowed when the verification was created through another form, or through no form at all (for example a bare API request or a dashboard request without a form). An id that does not exist in your organization is still a 404.
GET /v1/kyc/summary, GET /v1/kyc/analyticsComputed over the allowed forms' verifications only.
/v1/kyc/applicants…, /v1/kyc/deletion-requests…, /v1/kyc/reuse…, /v1/kyc/conferences…403 form_not_allowed — these are not tied to a form, so a form-restricted key cannot use them. Use an unrestricted key.

A renewal, or a UBO verification spawned by a business verification, belongs to the same form as the verification it came from.

Verifications that existed before this enforcement carry no form record until Certivant runs its one-time back-fill (from the form deliveries and form submissions already on file). Until then a form-restricted key will not see them. Verifications created by a key without a form restriction, with no form, stay invisible to form-restricted keys.

Workflow restriction

Certivant has no endpoint that names a workflow, so this restriction does not produce a 403 on any call. It controls which automation workflows may run for the verifications the key creates:

  • Every verification created by the key (POST /v1/kyc/requests, /requests/batch, POST /v1/kyc/forms/:formId/send, POST /v1/kyc/conferences with an inline applicant) records the key it came from.
  • From then on, for that verification only the workflows whose name is on the key's list may run — whatever fires the event: the applicant submitting the form, a decision, a reviewer, a webhook, or the key itself. Event-matched runs of any other workflow are skipped, and so is a workflow another workflow starts with a Trigger workflow step.
  • The key's current list applies while the key exists, so narrowing or lifting the restriction takes effect immediately on in-flight verifications. If the key is deleted, the list it had when it created the verification keeps applying.
  • Verifications created from the dashboard, by an applicant on a public form, or by a key without a workflow restriction are not affected, and neither is any other trigger (schedules, other verifications).
  • A renewal, and the UBO verifications of a business, inherit the restriction of the verification they come from.

The error reason workflow_not_allowed is reserved for endpoints that take a workflow by name; none exists today.

Live vs. test keys

ck_live_… keys are for production, ck_test_… keys for development and CI. The environment is a tag, not a sandbox: responses carry X-Certivant-Environment, the dashboard shows the badge, and audit entries record the key prefix — but a test key reads and writes the same data as a live key. The only sandbox is the tenant-level one: until Certivant has verified your organization, live verification features are blocked for every key. Use a separate organization if you need fully separate test data.

  • One key per environment. Mint separate keys for local, staging, and production. If you compromise one environment, the other two stay safe.
  • Label keys descriptively. payments-service-prod-2026Q2 beats key1. The label shows up in the audit log.
  • Set an expiry on keys you only need temporarily — for migrations, demos, or third-party access. Certivant rejects the key automatically once expiresAt passes.
  • Rotate annually. Mint a new key, switch your service to it, and revoke the old one once the new key has handled traffic without errors.
  • Never commit keys to git. Use your secrets manager — AWS Secrets Manager, GCP Secret Manager, Doppler, Infisical, or .env files in .gitignore at minimum.

Rotation in zero downtime

Use Rotate on the key (Developer → API keys), or the API:

POST /api/kyc/api-keys/{id}/rotate        (dashboard session, api.access permission)
{ "overlapHours": 24 }
sequenceDiagram
  participant You
  participant Dashboard
  participant Service
  participant Certivant
  You->>Dashboard: Rotate key (overlap 24 h)
  Dashboard-->>You: ck_live_new_… (same scopes, restrictions, IP allowlist)
  You->>Service: Deploy with new key in env var
  Service->>Certivant: Authenticated requests with new key
  Note over Certivant: Old key still works until the overlap ends
  Certivant-->>Service: Old key → 401 api_key_rotated after the overlap
  1. Rotate the key. The replacement copies the label, scopes, restrictions, IP allowlist and expiry; its full value is shown once.
  2. Deploy your service with the new key during the overlap (0–168 hours, default 24). The old key keeps working until then, and its Last used timestamp in the dashboard shows whether anything still calls it.
  3. When the overlap ends the old key returns 401 api_key_rotated. Use overlapHours: 0 to revoke it immediately. You can also revoke it earlier by hand.

What happens when a key is revoked

The next request using the revoked key returns 401. There is no grace period. If you accidentally revoke a key you still need, mint a new one — you cannot un-revoke.

Public endpoints (no key needed)

A small set of endpoints are intentionally public — they do not need an API key:

  • GET /api/health and GET /api/status — operational probes.
  • GET /api/branding — public branding config for the hosted UI.
  • GET /api/kyc/public/status?ref=… — applicant status lookup by external reference.
  • GET /api/kyc/public/forms/:slug and the form submission endpoints — used by the hosted form UI.

These are documented for completeness but most integrations never call them directly — the hosted session URL handles all public interaction.

Audit logging

Every authenticated API call is recorded in KycAuditLog with the calling key's prefix, the endpoint, and the actor type (api). You can review the trail at KYC → Audit log in the dashboard. Audit entries are retained for the full lifetime of the request they relate to.