Reference
API reference
The engine is REST over JSON and enforces HTTPS. Most endpoints are plain requests, but register and login carry zero-knowledge material that the client computes from the password, which is why the SDK generates it for you.
Base URL
https://api.zkauth.devAuthentication
Send your project key in x-api-key on every request. Routes that act on a signed-in user also need the session token as a bearer token. Bearer-only requests and invalid keys are rejected.
x-api-key: zka_live_<project_key> # every requestAuthorization: Bearer <session-token> # user routes onlyValidate a key
GET/api/v1/client/meReturns the client that owns a key: a fully self-contained request, so it’s the best first call to confirm your setup in any language.
curl https://api.zkauth.dev/api/v1/client/me \ -H "x-api-key: zka_test_<project_key>"Machine token introspection
POST/api/v1/m2m/introspectIntrospects the authenticated project API key as an opaque machine token. Send the key only in x-api-key; the body accepts optional exact issuer and audience assertions and rejects raw token or API-key fields.
POST /api/v1/m2m/introspect{ "issuer": "https://api.zkauth.dev", "audience": "zkauth:client:<client-id>"}{ "success": true, "data": { "active": true, "tokenType": "opaque", "tokenFormat": "zkauth_project_api_key", "subject": "client:<client-id>:key:<key-id>", "issuer": "https://api.zkauth.dev", "audience": "zkauth:client:<client-id>", "client": { "id": "<client-id>", "name": "Production", "status": "active" }, "key": { "id": "<key-id>", "prefix": "zka_live_abcd", "type": "live", "scopes": ["auth.login"], "expiresAt": null, "lastUsedAt": "2026-06-21T00:00:00.000Z", "rateLimitPerMinute": 100 } }}M2M boundary
Register
POST/api/v1/auth/registerThe body carries a client-derived salt and commitment, never the password. The SDK computes these; if you implement them yourself you must reproduce the Argon2id + Poseidon derivation.
POST /api/v1/auth/register{ "email": "ada@example.com", "salt": "...", // derived from the password on the client "commitment": "...", // Poseidon commitment, computed on the client "deviceInfo": { "deviceName": "Chrome on Mac", "deviceType": "desktop" }}You'll want the SDK here
commitment (register) and Groth16 proof (login) requires the circuits and crypto bundled in zkauth-client. Raw HTTP is best for the read, session, password-reset, OPAQUE, and WebAuthn endpoints below.Log in
GET/api/v1/auth/salt/:emailReturns the public salt for a user (the SDK fetches this for you).
POST/api/v1/auth/loginVerifies a Groth16 proof and applies replay protection.
- If user MFA is enabled, the response is a short-lived MFA challenge instead of a normal session.
- If project-required MFA is enabled and the user has no usable factor, login returns an enrollment-required response.
- The enrollment-only token is short-lived and can be used only for TOTP setup and verification.
POST /api/v1/auth/login{ "email": "ada@example.com", "proof": { "pi_a": [...], "pi_b": [...], "pi_c": [...], "protocol": "groth16", "curve": "bn128" }, "publicSignals": ["..."], "deviceInfo": { "deviceName": "Chrome on Mac", "deviceType": "desktop" }, "proofNonce": "...", "proofTimestamp": 1730000000000}Success response
{ "success": true, "data": { "token": "eyJ...", "user": { "id": "usr_...", "email": "ada@example.com", "emailVerified": true }, "session": { "sessionId": "...", "expiresAt": "..." } }}MFA challenge response
{ "success": false, "code": "MFA_REQUIRED", "data": { "mfaRequired": true, "token": "eyJ...", "availableMethods": ["totp", "backup"], "session": { "sessionId": "...", "type": "mfa_pending" } }}MFA enrollment-required response
{ "success": false, "code": "MFA_ENROLLMENT_REQUIRED", "data": { "mfaRequired": true, "enrollmentRequired": true, "token": "eyJ...", "availableMethods": [], "session": { "sessionId": "...", "type": "mfa_enrollment" } }}/api/v1/auth/verify-mfaExchanges the pending MFA token plus a TOTP or backup code for the authenticated session.
Hosted sign-in handoff
POST/api/v1/auth/hosted-handoffBearer-authenticated hosted UI endpoint that issues a short-lived, single-use handoff code for an allowlisted application callback. The response contains the redirect URL with code, not the bearer session token.
/api/v1/auth/hosted-handoff/redeemServer-side endpoint for application callbacks. Send the project API key and the handoff code to redeem the engine session token, then store it in your own secure app session cookie.
POST /api/v1/auth/hosted-handoff/redeem{ "code": "single_use_handoff_code"}Session identity and rotation
These require the session token as a bearer token.
GET/api/v1/auth/meReturn the authenticated user and current session metadata, including device, expiry, last activity, risk, MFA, and sensitive-session fields.
{ "success": true, "data": { "user": { "id": "usr_...", "email": "ada@example.com" }, "session": { "id": "sess_...", "type": "mfa_verified", "deviceId": "dev_...", "expiresAt": "2026-06-19T11:00:00.000Z", "lastActivityAt": "2026-06-18T11:50:00.000Z", "riskLevel": "low", "trustScore": 90, "mfaVerified": true, "sensitiveVerifiedAt": "2026-06-18T11:45:00.000Z", "sensitiveVerifiedFactor": "totp" } }}/api/v1/auth/logoutInvalidate the current session and revoke the active bearer token.
POST/api/v1/auth/refreshRotate the active session token and revoke the previous token.
- The default engine session lifetime is 24 hours, and project security policy can set a shorter or longer bounded lifetime.
- High-risk sessions may be shorter.
- Refresh preserves the original sensitive-session timestamp; it does not create a fresh MFA verification.
/api/v1/dashboard/statsGET/api/v1/dashboard/activityReturn user-scoped account statistics and recent login activity for the authenticated bearer session.
Hosted helper pages route these through the project-bound hosted proxy and bound displayed network/browser metadata before rendering.
GET/api/v1/auth/verify-email/:tokenConfirm an email with the token from registration.
Password reset
POST/api/v1/password/forgot-passwordGET/api/v1/password/verify-reset-tokenPOST/api/v1/password/reset-passwordRequest a reset, verify the token, then set a new commitment. Resets may require approval depending on your project policy. Password reset emails redirect to the project callback URL with zkauth_action=password_reset and token.
Devices
GET/api/v1/devicesPOST/api/v1/devices/registerPOST/api/v1/devices/verifyDELETE/api/v1/devices/:deviceIdGET/api/v1/device-approvals/approveGET/api/v1/device-approvals/denyGET/api/v1/device-approvals/pendingList, trust, verify, and remove a user’s devices. Device approval and denial links are separate single-use decisions; successful approval grants trust only inside the authenticated project.
OPAQUE
GET/api/v1/opaque/statusPOST/api/v1/opaque/register/responsePOST/api/v1/opaque/register/finishPOST/api/v1/opaque/login/startPOST/api/v1/opaque/login/finishPOST/api/v1/opaque/migration/startPOST/api/v1/opaque/migration/finishMigration endpoints support user-mediated movement from legacy password proof credentials to persisted OPAQUE records.
WebAuthn
POST/api/v1/webauthn/register/optionsPOST/api/v1/webauthn/register/verifyPOST/api/v1/webauthn/authenticate/optionsPOST/api/v1/webauthn/authenticate/verifyRoute these through your backend proxy so the key stays server-side. See Authentication.
Sessions & account security
User-scoped controls under /api/v1/security, all bearer-authenticated.
/api/v1/security/sessionsDELETE/api/v1/security/sessions/:sessionIdPOST/api/v1/security/sessions/terminate-othersGET/api/v1/security/devicesPATCH/api/v1/security/devices/:deviceId/trustDELETE/api/v1/security/devices/:deviceIdList active sessions with device/activity metadata, revoke a specific non-current session, or terminate every active session except the current one.
- Trusted-device listing, trust changes, and removals are scoped to the authenticated project.
- Removing a trusted device also invalidates matching sessions for that project.
- Terminating all other sessions requires a fresh first-factor session.
- Use
/auth/logoutto revoke the current session.
{ "success": true, "data": { "sessions": [ { "id": "sess_...", "deviceName": "Chrome on Windows", "deviceType": "desktop", "trustLevel": "trusted", "lastActivity": "2026-06-18T11:50:00.000Z", "expiresAt": "2026-06-19T11:00:00.000Z", "sessionType": "mfa_verified", "mfaVerified": true, "sensitiveVerifiedAt": "2026-06-18T11:45:00.000Z", "isCurrent": true } ], "total": 1 }}/api/v1/security/mfa/statusPOST/api/v1/security/mfa/totp/setupPOST/api/v1/security/mfa/totp/verifyPOST/api/v1/security/mfa/backup-codes/generatePOST/api/v1/security/mfa/disableGET/api/v1/security/recovery-codes/statusPOST/api/v1/security/recovery-codes/generatePOST/api/v1/security/recovery-codes/regeneratePOST/api/v1/security/recovery-codes/downloadTOTP setup and verification require a fresh first-factor session.
- When a project-required unenrolled login uses the enrollment-only token, successful TOTP verification returns a fresh MFA-backed engine session.
- Backup-code generation, recovery-code export, and MFA disable require a fresh MFA-backed session.
/api/v1/security/emergency-reset/requestPOST/api/v1/security/emergency-reset/confirmGET/api/v1/security/emergency-reset/statusPOST/api/v1/security/emergency-reset/cancelStart, confirm, inspect, or cancel account recovery. Confirming is gated by the configured delay.
Webhooks
Project-scoped webhook management endpoints.
GET/api/v1/client/webhooksPOST/api/v1/client/webhooksGET/api/v1/client/webhooks/eventsGET/api/v1/client/webhooks/:webhookIdPUT/api/v1/client/webhooks/:webhookIdDELETE/api/v1/client/webhooks/:webhookIdPOST/api/v1/client/webhooks/:webhookId/testGET/api/v1/client/webhooks/:webhookId/deliveriesPUT/api/v1/client/webhooks/bulkUse signed test deliveries before enabling production event delivery.
Transparency & evidence
Read-only endpoints that expose how the engine is actually configured, so you can verify our security claims instead of taking them on faith.
GET/api/v1/security/crypto-policyThe active cryptographic parameters (curve, hash, Argon2id settings).
GET/api/v1/security/standardsStandards mappings, published without claiming certification.
GET/api/v1/security/pq-readinessPost-quantum readiness posture.
GET/api/v1/security/evidenceGET/api/v1/security/assurance/policyAssurance and evidence records for operator and auditor review.
Key formats & limits
| Prefix | Use |
|---|---|
zka_live_... | Production traffic. |
zka_test_... | Development and CI. |
Rate limits apply per client. Failed requests return a non-2xx status with a JSON error envelope:
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "One or more fields are invalid.", "request_id": "req_...", "docs_url": "https://zkauth.dev/docs/errors#VALIDATION_ERROR" }, "code": "VALIDATION_ERROR", "message": "One or more fields are invalid.", "request_id": "req_..."}Prefer error.code and error.request_id in new integrations. The top-level fields are compatibility fields for older clients.