{id} must equal the token’s own subject — any mismatch is 403 forbidden, not a 404 (so a client can’t distinguish “not your account” from “doesn’t exist” by status code alone… actually here it deliberately does say “not yours”, since there’s no cross-account enumeration risk in a 1:1-scoped path).
GET /users/{id}
200 OK
PATCH /users/{id}
string
required
A fresh, single-use token from a passing
POST /verify/self — a stolen session/password alone can never authorize this.string
Optional.
string
Optional — a mutable BVN-linked field.
name, dateOfBirth, gender, or any other unlisted key is rejected at the schema level, not filtered out silently:
400 Bad Request
200 OK — phone change
200 OK — BVN-linked field change
pending_upstream, not applied — NIBSS-backed changes don’t apply instantly in the real system this simulates, so the client is told the old value still works until the change lands.
403 Forbidden — missing/stale/reused proofToken
DELETE /users/{id}
string
required
Same fresh-proof requirement as
PATCH — immediate re-authentication via /verify/self.200 OK
docs/RETENTION.md for the full ordering rationale and what’s purged vs. retained.
After deletion, GET /users/{id} and POST /verify/self both return 404 not_found for this user even with an otherwise-still-valid access token.