Skip to content

Backend API

All backend endpoints require Authorization: Bearer <API_KEY>. Keys identify the calling product; every action is audit-logged against a non-reversible key fingerprint. Never embed an API key in a mobile app, browser bundle, or repo.

Every API key belongs to a client (a business tenant). Keys look like bk_live_…, are shown exactly once at creation, and only their SHA-256 hash is stored server-side. All data access is scoped to the owning client: you can only read, review, erase, or attest verifications your own key created — anything else returns 404. Each client also gets its own whsec_… webhook signing secret (see Webhooks).

Clients are managed by the operator through the /v1/admin API, which is gated by a separate admin credential (BAQSHI_ADMIN_KEY, never a client key):

Terminal window
POST /v1/admin/clients {"name": "Acme Bank"} # → api_key + webhook secret, shown once
GET /v1/admin/clients # list (prefixes only, no secrets)
POST /v1/admin/clients/{id}/rotate-key # → new api_key, shown once
POST /v1/admin/clients/{id}/disable | /enable

Don’t have a key yet? Prospective clients can request access with POST /v1/access-requests {"company_name", "contact_name", "email", "message"?} (no auth, rate-limited) — the owner reviews requests in the admin panel and, on approval, hands over the credentials securely.

Lost keys cannot be recovered — rotate instead. Keys configured via the BAQSHI_API_KEYS environment variable act as the operator’s root client: they authenticate as before and can see every tenant’s verifications (for ops and manual review across tenants).

Terminal window
POST /v1/verifications
{ "external_user_ref": "user-123", "webhook_url": "https://yourapp.com/kyc-hook" }

Both fields are optional. webhook_url must be HTTPS. Response contains verification_id, handoff_token, handoff_url, expires_in_minutes.

Pattern: create verifications lazily, at the moment the user starts the flow — tokens live 30 minutes. If the user abandons and returns later, create a new one; old tokens die on their own.

Terminal window
GET /v1/verifications/{verification_id}

Returns status, decision_reasons, and the minimal extracted fields (names, DOB, document type/country/expiry). This endpoint is the only place extracted identity data leaves the system, and it requires the API key — the user’s device can never read it.

Prefer webhooks over polling; poll as a fallback with backoff (the pipeline usually decides in seconds, manual review in hours).

Terminal window
POST /v1/attestations/{verification_id}
{ "claims": ["verified", "over_18"] }

Only works for approved verifications (409 otherwise). Returns a signed compact token plus the claim values. See Attestations for verification and the claim catalogue.

Terminal window
DELETE /v1/verifications/{verification_id}/data

Cryptographic erasure for privacy/deletion requests: destroys every artifact’s data key, deletes hot blobs, and nulls the identity fields in the database. Blobs already on offline archive media become permanently unreadable too — no media handling required. The decision status and audit chain remain (you generally must keep that you verified someone; you stop keeping what you saw).

  • Creating a verification is not idempotent — dedupe on your side per user-session.
  • Reads are safe to retry.
  • Erasure is idempotent (already-erased artifacts are skipped).
  • On 429, respect Retry-After — see Rate limits.