Skip to main content
Crivacy Docs

API Reference

Base URL

All API requests are made to one of the following base URLs. Use the production URL for live integrations and the playground proxy for interactive testing from the dashboard.

  • https://api.crivacy.ioProduction API.
  • https://app.crivacy.io/api/internal/playgroundDashboard playground proxy. Uses the session cookie instead of an API key.

Authentication

Most endpoints require an API key sent via the x-api-key header. Dashboard endpoints use a session cookie (JWT). Admin endpoints require JWT plus TOTP verification. See the Authentication guide for details.

API version1.0.0OpenAPI3.1.0

Sessions

Create and read KYC verification sessions. A session represents an end user going through Didit identity capture before a credential is minted on Sepolia.

POST/api/v1/sessionsTry it

Create a KYC session

Starts a new verification session. Returns the Didit redirect URLs the end user must visit. The firm key must hold the kyc:create scope.

AuthAPI Key (X-API-Key)

Request body

Schema: SessionCreateRequest

Responses

201Session created. The redirectUrl in the response points at Didit phase 1.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/sessionsTry it

List KYC sessions

Cursor-paginated list of sessions, newest first.

AuthAPI Key (X-API-Key)

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.
statusqueryobjectoptional
Filter by lifecycle state.
userRefqueryobjectoptional
Exact match on userRef.
createdAfterqueryDateTimeIsooptional
ISO 8601 datetime in UTC (YYYY-MM-DDTHH:MM:SS.sssZ).
createdBeforequeryDateTimeIsooptional
ISO 8601 datetime in UTC (YYYY-MM-DDTHH:MM:SS.sssZ).

Responses

200Paginated list of sessions.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/sessions/{id}Try it

Read a KYC session

Returns the full session state including both Didit phases. Safe to poll; rate limit is the firm standard (60 req/s default).

AuthAPI Key (X-API-Key)

Parameters

idpathKycSessionIdrequired
Unique KYC session identifier.

Responses

200Session detail.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
DELETE/api/v1/sessions/{id}Try it

Cancel a KYC session

Marks a session as expired server-side. Has no effect if the session is already in a terminal state (approved, rejected, expired, revoked).

AuthAPI Key (X-API-Key)

Parameters

idpathKycSessionIdrequired
Unique KYC session identifier.

Responses

204Session canceled.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).

Credentials

Read and verify on-chain-issued KYC credentials. A credential is the immutable attestation that an end user passed the verification flow.

GET/api/v1/credentials/{userRef}Try it

Read a credential

Returns the active credential for userRef, including the on-chain pointer for independent verification. Responds with 404 (not_found) if no credential exists, 410 (credential_revoked) if the credential was revoked, or 200 for the active happy path. Requires kyc:read scope.

AuthAPI Key (X-API-Key)

Parameters

userRefpathUserRefrequired
Opaque identifier the firm uses for the end user. Any non-empty string up to 128 chars. Stored verbatim and returned verbatim; Crivacy does not interpret the value.

Responses

200Credential detail, including the on-chain pointer.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
POST/api/v1/credentials/verifyTry it

Verify a credential on chain

Reads the credential straight from the CrivacyKYC contract on Sepolia by the subject’s EVM address and returns { valid, reason, credential, verifiedAt }. Crivacy performs the read on the caller’s behalf; the plaintext lifecycle is public on chain. Requires kyc:verify scope.

AuthAPI Key (X-API-Key)

Request body

Schema: CredentialVerifyRequest

Responses

200Verification result. valid is false for any failure mode.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/credentials/{userRef}/historyTry it

Credential history

Returns the append-only history of lifecycle events for userRef. Includes all credentials ever issued, not just the current one. Requires kyc:read scope.

AuthAPI Key (X-API-Key)

Parameters

userRefpathUserRefrequired
Opaque identifier the firm uses for the end user. Any non-empty string up to 128 chars. Stored verbatim and returned verbatim; Crivacy does not interpret the value.

Responses

200Credential lifecycle history.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).

Webhooks

Manage webhook subscriptions for asynchronous events (credential lifecycle, session state changes).

GET/api/v1/webhooksTry it

List webhook subscriptions

Returns every webhook subscription owned by the firm. Requires webhooks:manage scope.

AuthAPI Key (X-API-Key)

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.

Responses

200Paginated list of subscriptions.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
POST/api/v1/webhooksTry it

Create a webhook subscription

Creates a new webhook subscription and returns the full signing secret exactly once. Store the secret immediately — every subsequent response masks it. Requires webhooks:manage scope.

AuthAPI Key (X-API-Key)

Request body

Schema: WebhookCreateRequest

Responses

201Subscription created. Contains the full signing secret.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/webhooks/{id}Try it

Read a webhook subscription

AuthAPI Key (X-API-Key)

Parameters

idpathWebhookSubscriptionIdrequired
Unique webhook subscription identifier.

Responses

200Subscription detail (secret masked).
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
PATCH/api/v1/webhooks/{id}Try it

Update a webhook subscription

Partially updates a subscription. Supports toggling active state, updating the URL, adjusting the event filter, or setting a new description. Requires webhooks:manage scope.

AuthAPI Key (X-API-Key)

Parameters

idpathWebhookSubscriptionIdrequired
Unique webhook subscription identifier.

Request body

Schema: WebhookUpdateRequest

Responses

200Updated subscription (secret masked).
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
DELETE/api/v1/webhooks/{id}Try it

Delete a webhook subscription

Hard-deletes the subscription. Pending deliveries for this subscription are dropped. Requires webhooks:manage scope.

AuthAPI Key (X-API-Key)

Parameters

idpathWebhookSubscriptionIdrequired
Unique webhook subscription identifier.

Responses

204Subscription deleted.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
POST/api/v1/webhooks/{id}/testTry it

Send a test event

Enqueues a synthetic delivery to the subscription URL. Returns 202 Accepted with the delivery id so the caller can poll GET /api/v1/webhooks/{id}/deliveries for the outcome.

AuthAPI Key (X-API-Key)

Parameters

idpathWebhookSubscriptionIdrequired
Unique webhook subscription identifier.

Request body

Schema: WebhookTestRequest

Responses

202Test delivery enqueued.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/webhooks/{id}/deliveriesTry it

List recent delivery attempts

Returns the most recent delivery attempts for a subscription, newest first.

AuthAPI Key (X-API-Key)

Parameters

idpathWebhookSubscriptionIdrequired
Unique webhook subscription identifier.
cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.

Responses

200Paginated delivery attempts.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).

Usage

Inspect API usage for the current billing period and historical months.

GET/api/v1/usageTry it

Current period usage

Returns the aggregate usage for the current calendar month. Requires usage:read scope.

AuthAPI Key (X-API-Key)

Responses

200Current month usage aggregate.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).
GET/api/v1/usage/historyTry it

Historical usage

Returns monthly usage aggregates for up to the past 24 months, newest first. Requires usage:read scope.

AuthAPI Key (X-API-Key)

Responses

200Historical usage rollup.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).

Limits

Read the tier configuration and remaining rate-limit / quota capacity for the authenticating API key.

GET/api/v1/limitsTry it

Rate limit and quota state

Returns the firm tier, the current token-bucket state, and the remaining monthly quota for the authenticating API key.

AuthAPI Key (X-API-Key)

Responses

200Tier + live rate limit + live quota snapshot.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401API key missing, malformed, or revoked (unauthenticated, invalid_api_key, expired_api_key).
403Key scope, firm tier, or IP allowlist disallows this call (scope_forbidden, tier_forbidden, ip_blocked).
404Resource does not exist or is not visible to the caller (not_found).
409Conflict or idempotency mismatch (conflict, idempotency_mismatch).
429Rate limit or monthly quota exhausted (rate_limited, quota_exceeded).
500Unhandled server error (internal_error).
502Upstream dependency (chain or Didit) unreachable (upstream_unavailable, chain_unavailable, didit_unavailable).
503Scheduled maintenance (maintenance).

Health

Liveness probes and public component status. Safe to hit without authentication.

GET/api/v1/healthTry it

Liveness probe

Aggregated liveness of the API. Returns 200 when every critical check passes, 503 (maintenance) otherwise. Safe to hit from unauthenticated monitoring tools.

Responses

200All checks green.
500Unhandled server error (internal_error).
503One or more health checks failed (maintenance).
GET/api/v1/statusTry it

Component status

Public component status view — identical data shown on the /status page. Returns 200 regardless of the underlying component states; the states themselves describe the outcome.

Responses

200Public status snapshot.
500Unhandled server error (internal_error).
503One or more health checks failed (maintenance).

Internal — Auth

Dashboard session management — login, logout, token refresh, TOTP enrollment.

POST/api/internal/auth/loginTry it

Dashboard login

Exchanges email + password (+ optional TOTP code) for a session cookie. Returns 401 (invalid_credentials) for any failure mode — email enumeration is intentionally impossible. When the firm requires TOTP but the user has not enrolled, the call still succeeds and requireTotpSetup is set to true so the UI can redirect into the enrollment flow.

Request body

Schema: LoginRequest

Responses

200Login successful. Set-Cookie: __Host-crv_session=... is attached.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/auth/logoutTry it

Dashboard logout

Invalidates the current dashboard session server-side and clears the cookie via Set-Cookie: __Host-crv_session=; Max-Age=0. Idempotent — calling logout without an active session still returns 204.

AuthDashboard Session

Responses

204Session cleared.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/auth/refreshTry it

Refresh the dashboard session

Extends the current session expiration by the configured dashboard session length (default 1 hour). Called by the dashboard opportunistically while the user is active.

AuthDashboard Session

Responses

200Session extended. A refreshed cookie is attached.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/auth/totp/setupTry it

Begin TOTP enrollment

Generates a new TOTP secret for the current user and returns it as an otpauth URL plus ten one-time recovery codes. The secret is not yet active — the user must confirm by calling POST /api/internal/auth/totp/verify with a valid code. Calling setup again before verifying replaces the staged secret.

AuthDashboard Session

Responses

200TOTP enrollment staged.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/auth/totp/verifyTry it

Confirm TOTP enrollment or supply a step-up code

Verifies a 6-digit TOTP code. When a staged secret from totp/setup is pending, this call activates it. When TOTP is already enabled, this call performs a step-up for privileged operations and refreshes the session with a short-lived step-up flag.

AuthDashboard Session

Request body

Schema: TotpVerifyRequest

Responses

200Verification result.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — Firm

Firm profile and settings for dashboard users.

GET/api/internal/firmTry it

Read firm profile

Returns the firm profile — branding, contact email, IP allowlist, data retention window. Any dashboard user can read.

AuthDashboard Session

Responses

200Firm profile.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
PATCH/api/internal/firmTry it

Update firm profile

Partially updates the firm profile. Each field in the request body is optional; at least one must be present. Requires the admin or owner firm-user role; the payload is validated against the same schema the public dashboard form uses.

AuthDashboard Session

Request body

Schema: FirmUpdateRequest

Responses

200Updated firm profile.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — API Keys

Dashboard-side API key issuance, rotation, revocation.

GET/api/internal/api-keysTry it

List API keys

Returns every API key issued to the firm, regardless of mode or revocation state. Cursor paginated.

AuthDashboard Session

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.

Responses

200Paginated list of API keys (prefixes only).
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/api-keysTry it

Create an API key

Mints a new API key and returns the full plaintext secret exactly once. Store the secret immediately — every subsequent response masks it. Requires the admin or owner firm-user role.

AuthDashboard Session

Request body

Schema: ApiKeyCreateRequest

Responses

201Key created. Contains the plaintext.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
DELETE/api/internal/api-keys/{id}Try it

Revoke an API key

Marks the key as revoked. Subsequent requests signed with the key will fail with 401. Revocation is irreversible; use POST /api/internal/api-keys/{id}/rotate when a rolling replacement is desired instead.

AuthDashboard Session

Parameters

idpathApiKeyIdrequired
Unique API key identifier.

Responses

204Key revoked.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/api-keys/{id}/rotateTry it

Rotate an API key

Issues a new plaintext secret for the same key record, revoking the previous plaintext. The key id, prefix display name, scopes, and mode are unchanged. The new plaintext is returned exactly once.

AuthDashboard Session

Parameters

idpathApiKeyIdrequired
Unique API key identifier.

Responses

200Key rotated. Contains the new plaintext.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — Usage

Dashboard usage charts fed by the aggregated usage rollups.

GET/api/internal/usage/chartsTry it

Hourly usage samples for dashboard charts

Returns dense hourly usage samples for the requested window. The endpoint is read-only and caches internally for 60 seconds, so multiple dashboard tabs rendering the same window share the same response body.

AuthDashboard Session

Parameters

fromqueryobjectrequired
Inclusive start of the chart window. Must be within the last 31 days; earlier dates are clamped.
toqueryobjectrequired
Exclusive end of the chart window. Must be greater than from and must not be in the future.

Responses

200Hourly usage chart data.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — Webhooks

Dashboard webhook delivery inspection and manual replay.

GET/api/internal/webhooks/deliveriesTry it

List webhook deliveries across all firm subscriptions

Returns webhook delivery attempts across every subscription owned by the firm, newest first. The dashboard uses this surface for the unified delivery log view. Cursor paginated.

AuthDashboard Session

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.
subscriptionIdquerystringoptional
Filter by webhook subscription id.
statusqueryobjectoptional
Filter by delivery status.

Responses

200Paginated delivery attempts.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).
POST/api/internal/webhooks/deliveries/{id}/replayTry it

Replay a webhook delivery

Requeues a previously-attempted delivery for another send. Safe to call on any delivery in a terminal state (succeeded, failed, dead); the worker will deduplicate at the HTTP level via the envelope id. Requires the admin or owner firm-user role.

AuthDashboard Session

Parameters

idpathWebhookDeliveryIdrequired
Unique webhook delivery attempt identifier.

Responses

202Delivery re-enqueued.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — Audit

Audit log readback for privileged firm operations.

GET/api/internal/audit-logTry it

Read the firm audit log

Returns audit-log rows scoped to the authenticated firm, filtered by the query parameters, newest first. Rows are never edited or deleted; retention is controlled by the firm dataRetentionDays setting. Requires the admin or owner firm-user role.

AuthDashboard Session

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.
actionquerystringoptional
actorKindqueryAuditActorKindoptional
Class of actor that authored an audit-log entry.
targetKindqueryAuditTargetKindoptional
Class of resource an audit-log entry refers to.
sincequeryDateTimeIsooptional
ISO 8601 datetime in UTC (YYYY-MM-DDTHH:MM:SS.sssZ).
untilqueryDateTimeIsooptional
ISO 8601 datetime in UTC (YYYY-MM-DDTHH:MM:SS.sssZ).

Responses

200Paginated audit log entries.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Internal — Playground

Interactive playground that proxies a request to the real public API using a test-mode API key.

POST/api/internal/playground/executeTry it

Proxy a request through a test-mode API key

Executes a public API request on behalf of the dashboard user using one of their test-mode API keys. The request and response are recorded in a dedicated playground log separate from the production usage table so playground traffic never contaminates billing or charts. Live-mode keys are rejected with 400 (invalid_argument).

AuthDashboard Session

Request body

Schema: PlaygroundExecuteRequest

Responses

200Response echoing the backing public-API call result.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Session missing, expired, or TOTP required (invalid_session, totp_required, totp_invalid).
403Role or scope denies the action (role_forbidden, permission_denied, scope_forbidden).
404Resource does not exist or is not owned by the firm (not_found).
409Conflict on create/update (conflict).
429Abuse throttle triggered (rate_limited).
500Unhandled server error (internal_error).

Admin — Firms

Crivacy admin — firm lifecycle, tier overrides, quota overrides, soft-delete.

GET/api/admin/firmsTry it

List firms

Returns every firm in the system, including soft-deleted records. Cursor paginated. Sort order is createdAt DESC.

AuthAdmin Session + TOTP

Parameters

cursorqueryPaginationCursoroptional
Opaque base64url pagination cursor issued by the API.
limitqueryPaginationLimitoptional
Page size. Must be in [1, 100], defaults to 25.

Responses

200Paginated list of firms.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
POST/api/admin/firmsTry it

Create a firm

Provisions a new firm record and its initial owner user. The response carries a one-shot password-reset URL valid for 24 hours — hand it to the firm operator out-of-band. No plaintext password is ever generated or stored.

AuthAdmin Session + TOTP

Request body

Schema: AdminFirmCreateRequest

Responses

201Firm created.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
GET/api/admin/firms/{id}Try it

Read a firm

Returns the admin view of a firm, including limit overrides and soft-delete state.

AuthAdmin Session + TOTP

Parameters

idpathFirmIdrequired
Unique firm identifier.

Responses

200Firm detail.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
PATCH/api/admin/firms/{id}Try it

Update a firm

Partially updates a firm — tier, per-firm rate-limit override, per-firm monthly quota override, data retention window. Any field not present in the request body is left untouched. Tier changes take effect immediately for subsequent requests.

AuthAdmin Session + TOTP

Parameters

idpathFirmIdrequired
Unique firm identifier.

Request body

Schema: AdminFirmUpdateRequest

Responses

200Updated firm.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
DELETE/api/admin/firms/{id}Try it

Soft-delete a firm

Marks the firm as soft-deleted. All firm users are immediately logged out, every API key is revoked, and outbound webhooks are disabled. The firm record is retained for audit and billing; hard deletion happens through a separate retention job, not this endpoint.

AuthAdmin Session + TOTP

Parameters

idpathFirmIdrequired
Unique firm identifier.

Responses

204Firm soft-deleted.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).

Admin — System

Crivacy admin — internal system metrics, queue depths, operational dashboards.

GET/api/admin/system/metricsTry it

Live system metrics

Returns live internal metrics — db pool state, chain reachability, didit reachability, recent HTTP error rate. Not cached; every call hits the in-process metric registry.

AuthAdmin Session + TOTP

Responses

200Live metrics snapshot.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
GET/api/admin/system/queuesTry it

pg-boss queue depth

Returns the pending/active/completed/failed count for every background queue, plus the oldest pending job timestamp. Used by the admin dashboard to detect stuck workers.

AuthAdmin Session + TOTP

Responses

200Queue state snapshot.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).

Admin — Status

Crivacy admin — publish incidents and component state updates to the public status page.

POST/api/admin/status/incidentTry it

Publish an incident

Creates a new status-page incident. When publish is true (the default) the incident is immediately visible to unauthenticated callers hitting GET /api/v1/status; otherwise the incident is staged as a draft and can be published later via PATCH. Linked components are switched to degraded_performance or worse depending on the incident severity.

AuthAdmin Session + TOTP

Request body

Schema: AdminIncidentCreateRequest

Responses

201Incident created.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).
POST/api/admin/status/componentTry it

Update a component state manually

Overrides the automated state of a status-page component. When manualOverride is true (the default), subsequent probe results will not overwrite the state until the override is cleared by another manual update with state: operational. Used to force a component into maintenance during planned work.

AuthAdmin Session + TOTP

Request body

Schema: AdminComponentUpdateRequest

Responses

200Component state updated.
400Request failed schema validation (validation_failed, invalid_request, malformed_json).
401Admin session missing or expired (invalid_session).
403Caller is not a Crivacy admin or lacks the required permission (role_forbidden, permission_denied).
404Resource does not exist (not_found).
409Conflict on create/update (conflict).
500Unhandled server error (internal_error).

Incoming Webhooks

Endpoints Crivacy hosts to receive events from upstream providers (currently Didit).

POST/api/webhooks/diditTry it

Didit webhook receiver

Receives verification decisions from Didit. The request must carry a valid X-Signature-V2 HMAC header computed over the raw request body using the shared webhook secret. The response is 200 received even when the embedded decision is a rejection — the HTTP status reports whether Crivacy accepted the delivery, not the decision outcome.

AuthWebhook Signature

Request body

Schema: DiditWebhookPayload

Responses

200Delivery accepted and enqueued.
400Request failed schema validation (validation_failed, malformed_json).
401HMAC signature missing or invalid (webhook_signature_invalid).
404Subscription not found (not_found).
413Payload exceeds the accepted size limit (payload_too_large).
500Unhandled server error (internal_error).
API Reference -- Crivacy Docs