KYC API
Identity verification surface across three cooperating layers: oracle-bridge adapter (provider-agnostic REST at /api/kyc/*), Verifiable Credential bridge (W3C VC Data Model v1.1 + Ed25519Signature2020 proof, SHA-256 canonical hash), and embedded frontend widget (KycWidget React component in marketing-suite).
Services: oracle-bridge · membership canister · marketing-suite (KycWidget) Providers: Didit (primary) · iDenfy (hot backup) · blockpass (reserved) Epic: KYC-001 (completed 2026-04-15)
For the full reference including endpoints, schemas, Mermaid lifecycle diagram, on-chain attestation invariants, DB schema, env vars, and the widget state machine, see the root API reference at api/kyc.md.
Quick Reference
oracle-bridge REST endpoints
| Method | Path | Auth | Purpose |
|---|---|---|---|
POST | /api/kyc/session | session + CSRF | Create a verification session with the active provider |
GET | /api/kyc/status/:userId | session + CSRF | Latest verification row for the caller (or any user if admin) |
GET | /api/kyc/attestation[?user_id=] | session + CSRF | Latest live attestation (VC + hash + metadata) |
GET | /api/kyc/attestation/by-principal/:principal | admin session | Admin inspection by IC principal |
POST | /api/kyc/webhook | provider HMAC-SHA256 | Provider callback — drives membership + attestation bridges |
POST | /api/kyc/admin/retry-unsynced | admin session | Replay approved verifications whose canister call failed |
POST | /api/kyc/admin/retry-attestations | admin session | Replay attestations whose canister sync failed |
The webhook route is mounted before express.json() and uses express.raw({ type: '*/*', limit: '1mb' }) so HMAC signature verification operates on the exact provider bytes. Re-ordering breaks verification 100%.
Membership canister methods (KYC attestation)
| Method | Kind | Access | Purpose |
|---|---|---|---|
set_kyc_attestation | update | oracle-bridge principal only (require_oracle_bridge) | Insert or replace a 32-byte SHA-256 hash + metadata record |
get_kyc_attestation | query | public | Fetch the attestation (hash + metadata, no PII) |
revoke_kyc_attestation | update | controller only | Mark revoked (row retained for audit) |
is_kyc_verified | query | public | Predicate: exists AND not revoked AND not expired |
Normalized Status Values
Every provider-native status collapses into:
type KycStatus = 'PENDING' | 'APPROVED' | 'DENIED' | 'REVIEW';Unknown strings collapse to REVIEW (fail-closed — never silent-approve).
KycWidget Component
import KycWidget from '@/components/KycWidget';
<KycWidget
userId={session.userId} // required
callbackUrl="https://.../kyc-verification" // required
onSuccess={(status) => { /* APPROVED */ }}
onFailure={(reason, status) => { /* DENIED | REVIEW | null */ }}
pollIntervalMs={3000} // default 3s
maxPolls={30} // default 30 (≈90s)
/>State machine: loading → ready → polling → { approved | rejected | error }. Provider postMessage origin is verified against the iframe origin; terminal states fire onSuccess / onFailure exactly once (guarded against React Strict Mode double-renders).
Related
- Repository — oracle-bridge (
src/routes/kyc.ts,src/kyc/) - Repository — membership (
src/lib.rsKYC attestation methods) - Repository — marketing-suite (
src/components/KycWidget/) - Full API reference
- governance — uses
is_kyc_verifiedfor voting + ratification gates - payment-gateway —
kyc-refundpayment type - cross-domain-auth — session-cookie pattern shared by
/api/kyc/*