BIO.RE
Creator

Start KYC Verification

Initiate identity verification with the active KYC provider. Returns a redirect URL for the hosted verification flow. Vendor identity is admin-managed — clients receive an opaque provider id.

POST /api/v1/creators/kyc/start — 🔑 Bearer · Rate limit: 5 req / hour

Starts an identity verification session with the active KYC provider (admin-managed via external.kyc.active_provider; failover handled server-side). Returns a hosted-flow redirectUrl plus opaque sessionId and provider identifier — the client opens the URL, the user completes verification on the provider's site, and the provider notifies us via webhook.

Admin kill switch. When the KYC kill switch is active (admin-managed), every call returns 503 features.kyc_disabled regardless of state. Surface a "verification temporarily unavailable" UI when you see that response.

The provider field in the response is the active provider's identifier string (e.g. "<provider-id>"). It's opaque to clients — don't branch on its value, don't display it. It exists for support / debugging trails. Vendor identity stays in admin; this endpoint guarantees a session via whichever provider is active.

Request

No body, no params. Identity comes from the bearer token.

HeaderRequiredNotes
Authorization: Bearer <accessToken>JWT from POST /auth/login

Response

201 CreatedApiResponseOf<KycStartResponseDto>

{
  "success": true,
  "data": {
    "redirectUrl": "https://provider.example.com/verify?session=...",
    "sessionId": "sess_...",
    "provider": "<provider-id>"
  }
}
FieldTypeNotes
redirectUrlstringOpen this URL in a popup or full-page redirect. The user completes ID upload + biometrics on the provider's hosted flow.
sessionIdstringThe provider's session id — useful only for support tickets.
providerstringIdentifier of the active KYC provider (admin-managed). Treat as opaque.

Errors

HTTPcode / i18nKeyReason
400(KYC service)Already approved or in-progress (provider-specific message)
401(guard)Missing / invalid bearer token
404error.creator.not_foundNo CreatorProfile for this user — call POST /creators/upgrade first
429(throttle)Rate limit exceeded (5 req/hour)
503features.kyc_disabledAdmin kill switch KYC is active

Side effects

  1. Kill switch check (@RequireKillSwitch('KYC')) — if active, throw 503 features.kyc_disabled before reaching the service.
  2. Lookup CreatorProfile by userId; throw not_found if missing.
  3. Delegate to creatorLevelService.startKYC(creator.id)kycService.startVerification(creator.id):
    • Resolve the active KYC provider from admin config.
    • Create a verification session via the provider's API (server-to-server).
    • Persist kycProvider + kycProviderId + flip kycStatus to PENDING on CreatorProfile.
    • Return { redirectUrl, sessionId, provider }.
  4. The user completes verification out-of-band; the provider's webhook (handled by webhooks/kyc/*, internal scope) flips kycStatus to APPROVED / REJECTED and sets kycCompletedAt.

Code samples

curl -X POST https://api.bio.re/api/v1/creators/kyc/start \
  -H "Authorization: Bearer $ACCESS_TOKEN"
type KycStart = {
  redirectUrl: string;
  sessionId: string;
  provider: string;
};

async function startKyc(accessToken: string): Promise<KycStart> {
  const res = await fetch('https://api.bio.re/api/v1/creators/kyc/start', {
    method: 'POST',
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  const json = await res.json();
  if (!res.ok || !json.success) {
    throw Object.assign(new Error(json?.error?.message ?? 'KYC start failed'), {
      code: json?.error?.code,
    });
  }
  return json.data;
}

// Usage: open redirectUrl in a popup or full-page redirect
function launchKyc(redirectUrl: string) {
  window.location.assign(redirectUrl);
}
import { useMutation, useQueryClient } from '@tanstack/react-query';

export function useStartKyc() {
  const qc = useQueryClient();
  return useMutation({
    mutationFn: async () => {
      const res = await fetch('/api/v1/creators/kyc/start', { method: 'POST' });
      const json = await res.json();
      if (!res.ok || !json.success) {
        throw Object.assign(new Error(json?.error?.message ?? 'KYC start failed'), {
          code: json?.error?.code,
          i18nKey: json?.error?.i18nKey,
        });
      }
      return json.data as KycStart;
    },
    onSuccess: () => {
      // Status will flip to PENDING server-side
      qc.invalidateQueries({ queryKey: ['creators', 'kyc', 'status'] });
      qc.invalidateQueries({ queryKey: ['creators', 'profile'] });
    },
  });
}

Try it

POST
/api/v1/creators/kyc/start
AuthorizationBearer <token>

In: header

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://loading/api/v1/creators/kyc/start"
{
  "success": true,
  "data": {
    "redirectUrl": "https://provider.example.com/verify?session=abc123",
    "sessionId": "sess_abc123",
    "provider": "sumsub"
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
{
  "success": false,
  "error": {
    "code": "AUTH_UNAUTHORIZED",
    "message": "Invalid credentials",
    "i18nKey": "auth.login.invalid_credentials",
    "i18nVars": {
      "field": "email"
    },
    "details": [
      {
        "message": "email must be an email"
      }
    ],
    "correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Source

SourcePathLines
Controllerapps/api-core/src/modules/creator/creator.controller.ts277–291 (startKyc)
DTO (response)apps/api-core/src/modules/creator/dto/creator-client-response.dto.ts547–556 (KycStartResponseDto)
Serviceapps/api-core/src/modules/creator/creator-level.service.ts150–152 (startKYC — delegates to KycService)
KYC serviceapps/api-core/src/modules/creator/kyc/kyc.service.tsstartVerification() (provider abstraction)
Kill switchapps/api-core/src/common/guards/kill-switch.guard.tsRequireKillSwitch('KYC')
Config(admin-managed)external.kyc.active_provider ConfigService key
Prisma modelpackages/prisma/prisma/schema.prismaCreatorProfile.kycStatus (enum KycStatus), CreatorProfile.kycProvider, CreatorProfile.kycProviderId

On this page