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) orck_test_(test). Older keys that start withkyk_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.reason | HTTP | Meaning |
|---|---|---|
missing_api_key | 401 | No Authorization: Bearer … header. |
invalid_api_key | 401 | Unknown key (typo, truncated, wrong organization). |
api_key_revoked | 401 | The key was revoked. |
api_key_expired | 401 | The key's expiresAt has passed. |
api_key_rotated | 401 | The key was rotated and its overlap window ended — use the replacement. |
insufficient_scope | 403 | The key lacks the scope this endpoint needs. |
ip_not_allowed | 403 | The caller's address is not on the key's IP allowlist. |
form_not_allowed | 403 | The key is restricted to other forms — see Form restriction. |
workflow_not_allowed | 403 | Reserved 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
| Scope | What it allows |
|---|---|
kyc:read | Read requests, list/get documents, fetch fraud signals, read KYB data, list forms, read analytics |
kyc:write | Create requests, upload documents, resubmit a rejected request, generate hosted session URLs, submit KYB entity data, send forms, schedule live verifications |
kyc:submit | POST /requests/:id/submit — release a request to automated processing |
kyc:manage | Override 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.
| Resource | Scopes | Endpoints |
|---|---|---|
verifications | read · write · submit · manage | /v1/kyc/requests… (incl. KYB, EDD, fraud signals) |
documents | read · write · manage | /v1/kyc/requests/:id/documents… |
forms | read · write · manage | /v1/kyc/forms…, /v1/kyc/deliveries… |
live_id | read · write | /v1/kyc/conferences… |
analytics | read | /v1/kyc/analytics, /v1/kyc/summary |
privacy | manage | /v1/kyc/deletion-requests…, /v1/kyc/applicants… (erasure, export) |
webhooks | read · manage | Webhook 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 with403 ip_not_allowed. - Expiry — after
expiresAtthe key returns401 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.
| Call | Behaviour for a form-restricted key |
|---|---|
GET /v1/kyc/forms | Lists only the allowed forms. |
POST /v1/kyc/forms/:formId/send, GET /v1/kyc/forms/:formId/deliveries, GET /v1/kyc/deliveries/:id | 403 form_not_allowed for any other form (a delivery of another form included). |
POST /v1/kyc/requests and each item of /requests/batch | The 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/requests | Lists 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/analytics | Computed 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/conferenceswith 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.
Recommended environment hygiene
- One key per environment. Mint separate keys for
local,staging, andproduction. If you compromise one environment, the other two stay safe. - Label keys descriptively.
payments-service-prod-2026Q2beatskey1. 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
expiresAtpasses. - 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
.envfiles in.gitignoreat 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
- Rotate the key. The replacement copies the label, scopes, restrictions, IP allowlist and expiry; its full value is shown once.
- 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.
- When the overlap ends the old key returns
401 api_key_rotated. UseoverlapHours: 0to 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/healthandGET /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/:slugand 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.