KYC and compliance

All routes require x-api-key; none requires an API-key permission flag. KYC routes additionally require a bearer session. Compliance routes accept a valid session, x-profile-id plus x-team-id, or a team/profile-scoped API key.

For business teams, an admin profile uses the team KYB workflow for session creation and status. Every other profile uses the user’s KYC workflow.

Endpoints#

MethodPathContextSuccess
POST/v1/kyc/sessionSession201
GET/v1/kyc/statusSession200
GET/v1/kyc/verificationsSession200
POST/v1/compliance/checkoutSession, headers, or scoped key200
POST/v1/compliance/pay-via-requestSession, headers, or scoped key200

API-key failures return 403, rate limits return 429, and required-session failures return 401.

POST /v1/kyc/session#

Creates a hosted identity-verification session for the current profile.

Headers: x-api-key, Authorization: Bearer <session>, and Content-Type: application/json.

FieldTypeRequiredConstraints
emailstringYesValid email.
metadataobjectNoString keys and arbitrary JSON values; defaults to {}.
{
	"success": true,
	"data": {
		"sessionUrl": "https://verify.example/session/abc123",
		"verificationId": "verification-session-id",
		"status": "not started"
	}
}

The provider status is lowercased in the normal workflow. Staging environments can return an immediately approved demo session instead of a live provider session.

StatusCodeMessage
400APP_V1_KYC_SESSION_ROUTE_01Missing profile context
400body parser codeInvalid request body
404APP_V1_KYC_SESSION_ROUTE_04Profile not found
404propagatedProfile lookup failed
500propagatedProvider session or verification-record creation failed

GET /v1/kyc/status#

Returns the latest applicable verification status: team KYB for a business-team admin, otherwise user KYC.

Headers: x-api-key and Authorization: Bearer <session>.

When a verification exists:

{
	"success": true,
	"data": {
		"isVerified": true,
		"status": "approved",
		"verification": {
			"id": "verification-uuid",
			"verificationId": "provider-session-id",
			"status": "approved",
			"verficationProvider": "didit",
			"createdAt": "2026-07-28T17:00:00.000Z",
			"data": {}
		}
	}
}

When no user KYC verification exists, isVerified is false, status is none, and verification is null. verficationProvider is the response field’s current spelling.

StatusCodeMessage
400APP_V1_KYC_STATUS_ROUTE_01Missing profile context
404APP_V1_KYC_STATUS_ROUTE_02Profile not found
404 or 500propagatedProfile or verification lookup failed

GET /v1/kyc/verifications#

Lists all user KYC verification records newest first. This route does not switch to team KYB for business admins.

Headers: x-api-key and Authorization: Bearer <session>.

{
	"success": true,
	"data": [
		{
			"id": "verification-uuid",
			"verificationId": "provider-session-id",
			"status": "approved",
			"verficationProvider": "didit",
			"createdAt": "2026-07-28T17:00:00.000Z",
			"data": {}
		}
	]
}

verficationProvider is intentionally spelled as returned by the API.

StatusCodeMessage
400APP_V1_KYC_VERIFICATIONS_ROUTE_01Missing profile context
404APP_V1_KYC_VERIFICATIONS_ROUTE_04Profile not found
404propagatedProfile lookup failed
500propagatedVerification lookup failed

Compliance context#

Compliance routes use the first valid context source:

  1. A valid bearer session’s current profile/team.
  2. x-profile-id and x-team-id, validated as a membership.
  3. The API key’s own team/profile scope.

For header context, send both headers. An invalid or unavailable context returns 401 from context resolution or 400 from the route. These routes do not require an admin role.

POST /v1/compliance/checkout#

Creates a hosted yearly compliance-fee subscription checkout.

Headers: x-api-key (required); one compliance context source; Content-Type: application/json when sending a body.

The body may be omitted or be {}.

FieldTypeRequiredConstraints
successUrlstringNoValid URL. Overrides the configured success redirect.
cancelUrlstringNoValid URL. Overrides the configured cancel redirect.

If either field is omitted, the route uses its configured default. Both resolved URLs must exist.

{
	"success": true,
	"data": {
		"checkoutUrl": "https://checkout.example/session/abc123",
		"sessionId": "checkout-session-id",
		"mode": "subscription"
	}
}

checkoutUrl can be null if the payment provider creates a session without a URL.

StatusCodeMessage
400APP_V1_COMPLIANCE_CHECKOUT_ROUTE_01Missing profile context
404APP_V1_COMPLIANCE_CHECKOUT_ROUTE_02Profile not found
400APP_V1_COMPLIANCE_CHECKOUT_ROUTE_03Missing checkout redirect URLs
500APP_V1_COMPLIANCE_CHECKOUT_ROUTE_04Failed to create Stripe checkout session
500APP_V1_COMPLIANCE_CHECKOUT_ROUTE_05Vudy channel not found
400APP_V1_COMPLIANCE_CHECKOUT_ROUTE_06Invalid JSON body / Invalid body
500propagatedProfile, configuration, channel, or payment-provider lookup failed

POST /v1/compliance/pay-via-request#

Gets or creates an on-chain compliance-fee payment request for the active team.

Headers: x-api-key (required) plus one compliance context source. There is no request body.

When a pending request already exists:

{
	"success": true,
	"data": {
		"amountUsd": 100,
		"customId": "compliance-fee-team-uuid",
		"id": "request-uuid",
		"url": "/request/request-id",
		"embedUrl": "/request/embed/request-id"
	}
}

When a request is created, data always contains amountUsd and customId plus the public fields returned by the request-creation operation. That operation is not narrowed to a route-specific response schema in the implementation.

StatusCodeMessage
400APP_V1_COMPLIANCE_PAY_VIA_REQUEST_ROUTE_01Missing profile context
404APP_V1_COMPLIANCE_PAY_VIA_REQUEST_ROUTE_02Payer profile not found
500APP_V1_COMPLIANCE_PAY_VIA_REQUEST_ROUTE_03COMPLIANCE_FEE_MAKER_PROFILE_ID is required
404APP_V1_COMPLIANCE_PAY_VIA_REQUEST_ROUTE_04Maker profile not found
500APP_V1_COMPLIANCE_PAY_VIA_REQUEST_ROUTE_05Vudy channel not found
500propagatedProfile, pending-request, channel, or request creation failed