http://localhost:3000. All request/response bodies are JSON except where noted (image uploads use multipart/form-data).
Auth
Two independent subject types, never mixed sessions:- Consumer —
POST /auth/otp/request/POST /auth/otp/verify→ JWT access token + opaque refresh token. - Operator —
POST /auth/operator/login(admin-issued credentials only, no self-registration) → same token shape, plus amustResetPasswordflag enforced server-side on every other operator endpoint until cleared viaPOST /auth/operator/set-password.
Authorization: Bearer <accessToken>.
Error shape
Every error response is{ "error": "<stable_code>", "message": "<human text>" }, sometimes with a details object. Distinct-outcome endpoints (verify-face, /identify, /verify/self) also echo the code as outcome in the body, e.g.:
Modules
- Auth — OTP, operator login, session refresh.
- Identity Linking — NIN/BVN validate → verify-face → link (Epic 2+3, enrollment is a side effect of this).
- Verification —
/identify(1:N),/verify/self(1:1). - Profile —
GET/PATCH/DELETE /users/{id}. - Audit & History — verification history, CSV export, operator session logs.
- Disputes
- Operators — admin-only staff management.
- Analytics & Billing
- Preferences
- System —
/health,/models,/settings/attestation-required.