Developer documentation

Build on verified humans.

KYCPort is reusable identity infrastructure. Your users verify once and you read their assurance — KYC status and tier — instead of re-collecting documents. Standard OAuth2 / OpenID Connect, a thin BFF on your side, no tokens in the browser.

Concept

Verify once, reuse everywhere

You are a tenant (relying party). You register an OAuth/OIDC client and receive a client_id (and a client_secret for confidential clients). You never receive a user's documents — only the verification result.

Every verified human carries a reusable assurance: a status (verified · pending · rejected · unverified · expired) and an assurance tier (t0…t3). You request the tier you need; KYCPort tells you whether the human meets it.

Security model. Browser apps must run a Backend-for-Frontend. Tokens and the client_secret live only on your server; the browser holds an httpOnly session cookie. Never store a token in localStorage or ship a secret to the client. HTTPS (TLS 1.2+) everywhere.

Quickstart

Sign in with KYCPort

The Authorization Code flow with PKCE is the only supported browser flow.

1. Discover endpoints (always start here, never hardcode):

GET https://www.kycport.com/api/oidc/.well-known/openid-configuration
# -> issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri

2. Redirect the user to authorize with PKCE + state:

GET /authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://app.example.com/callback   # exact-match registered, HTTPS
  &scope=openid email kyc
  &state=RANDOM_CSRF
  &nonce=RANDOM_NONCE
  &code_challenge=BASE64URL(SHA256(verifier))
  &code_challenge_method=S256

3. Exchange the returned code for tokens on your server:

POST /api/oidc/token/
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://app.example.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET      # confidential clients
&code_verifier=ORIGINAL_VERIFIER

# -> { id_token, access_token, token_type: "Bearer", expires_in }
# Tokens are JWTs signed EdDSA (Ed25519); access tokens carry typ: at+jwt.

4. Validate every token — signature via jwks_uri, iss == https://www.kycport.com, aud == client_id, exp, and the nonce — then create your session.

Auth rules

Non-negotiable

  • PKCE is required. S256 only; plain is rejected.
  • state + nonce. Bind state to the session and reject mismatches; validate nonce in the ID token.
  • Least-privilege scopes. openid (required), plus email, profile, kyc as needed.
  • Exact redirect URIs. HTTPS, registered ahead of time, exact match.

Reusable identity

Read a user's verification status

With the kyc scope the status is in the ID token / userinfo (no extra call). Or fetch it server-to-server with your tenant API key:

GET /api/v1/kyc/{person_id}/status/
Authorization: Bearer YOUR_TENANT_API_KEY

# -> { "kyc_status": "verified", "kyc_tier": "t2", "aml_clear": true }
# Field names are exactly kyc_status and kyc_tier.

If the user isn't at your required tier, send them through verification and re-check — don't collect documents yourself.

Optional

Host your own capture

If you run the capture UI instead of redirecting, use the tenant-key case API:

POST /api/v1/verification/cases/                 # { person_id, level } -> opens a case
POST /api/v1/verification/cases/{id}/upload/    # multipart: document, selfie, document_back?, liveness_mode?, applicant_*?
POST /api/v1/verification/cases/{id}/decide/    # -> { outcome, risk_level, human_verified, automation_tier }

The engine runs real document forensics, liveness / presentation-attack detection, and face-match with 1:N dedup. Never submit a precomputed verdict — the score is always computed server-side.

Events

Webhooks

Subscribe to verification and status-change events. Each delivery is signed (HMAC over the raw body) — verify the signature before trusting it, make handlers idempotent (deliveries can repeat), return 2xx quickly, and let KYCPort retry with backoff on failures.

Ship safely

Best-practices checklist

  • Confidential client + client_secret on the server only; rotate periodically.
  • PKCE S256 on every authorize; state + nonce validated on callback.
  • Validate iss, aud, exp, and EdDSA signature (via jwks) on every token.
  • Browser holds only an httpOnly, Secure, SameSite=Lax session cookie — never a token.
  • Least-privilege scopes; cache the tier, re-check on sensitive actions.
  • Idempotent webhook handlers with signature + replay protection.
  • All redirect URIs HTTPS and exact-match registered.
  • Act on the JSON error field; retry only idempotent GET/5xx with backoff; respect 429.

AI coding assistant? Fetch /llms.txt — it's the same guidance in a literal, copy-paste-ready form.