Verify API
The Verify API powers KYC verification. Organizations register, create verification sessions, and receive results through webhooks or polling. End users complete verification through a hosted flow or direct API calls.
Base URL: https://verify.solidus.network/v1
Authentication
Register
Create a new organization account.
POST /auth/register
Auth: None
// Request body
{
"email": "[email protected]",
"password": "secureP@ssw0rd!",
"name": "Acme Corp"
}// Response 201
{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "usr_8Kj2mNpQxR",
"email": "[email protected]",
"name": "Acme Corp",
"organizationId": "org_3Vn9wLkDfT",
"createdAt": "2026-05-07T10:30:00Z"
}
}Login
Authenticate with email and password. If TOTP is enabled, a totpCode is required.
POST /auth/login
Auth: None
// Request body
{
"email": "[email protected]",
"password": "secureP@ssw0rd!"
}// Response 200 — success
{
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "usr_8Kj2mNpQxR",
"email": "[email protected]",
"name": "Acme Corp",
"organizationId": "org_3Vn9wLkDfT"
}
}// Response 200 — TOTP required
{
"totpRequired": true
}When totpRequired is true, resend the login request with the totpCode field.
// Request body with TOTP
{
"email": "[email protected]",
"password": "secureP@ssw0rd!",
"totpCode": "482901"
}Get Current User
Retrieve the authenticated user and organization details.
GET /auth/me
Auth: JWT Bearer
curl https://verify.solidus.network/v1/auth/me \
-H "Authorization: Bearer eyJhbGciOiJFZERTQSIs..."// Response 200
{
"organization": {
"id": "org_3Vn9wLkDfT",
"name": "Acme Corp",
"email": "[email protected]",
"plan": "starter",
"totpEnabled": false,
"createdAt": "2026-05-07T10:30:00Z"
}
}Setup TOTP
Generate a TOTP secret and QR code for two-factor authentication.
POST /auth/totp/setup
Auth: JWT Bearer
// Response 200
{
"secret": "JBSWY3DPEHPK3PXP",
"qrCode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
}Enable TOTP
Confirm TOTP setup by providing the secret and a valid code from the authenticator app.
POST /auth/totp/enable
Auth: JWT Bearer
// Request body
{
"secret": "JBSWY3DPEHPK3PXP",
"totpCode": "482901"
}// Response 200
{
"message": "TOTP enabled successfully"
}Forgot Password
Send a password reset email.
POST /auth/forgot-password
Auth: None
// Request body
{
"email": "[email protected]"
}// Response 200
{
"message": "If an account with that email exists, a reset link has been sent"
}Reset Password
Set a new password using the token from the reset email.
POST /auth/reset-password
Auth: None
// Request body
{
"token": "rst_7Hk3mRtQZvXp2...",
"password": "newSecureP@ssw0rd!"
}// Response 200
{
"message": "Password reset successfully"
}OAuth Login
Redirect the user to Google or GitHub for OAuth authentication. After authorization, the user is redirected back with a JWT.
GET /auth/google — Redirects to Google OAuth
GET /auth/github — Redirects to GitHub OAuth
Verification Sessions
Create a Session
Create a new verification session. The response includes a sessionUrl that you can redirect users to for the hosted verification flow.
POST /verifications
Auth: API Key (x-api-key)
// Request body
{
"level": 2,
"sandbox": false,
"redirectUrl": "https://acme.com/onboarding/complete",
"subjectDid": "did:solidus:testnet:7Hk3mRtQZvXp2nBw9Lj4K",
"metadata": {
"userId": "usr_acme_12345",
"plan": "premium"
}
}| Field | Type | Required | Description |
|---|---|---|---|
level | 1 | 2 | 3 | Yes | Verification level. 1 = document only, 2 = document + liveness, 3 = document + liveness + address proof |
sandbox | boolean | No | If true, runs in sandbox mode with no real verification |
sandboxOutcome | string | No | Force a sandbox result: "approved", "rejected", "error" |
subjectDid | string | No | Associate the session with a specific DID |
redirectUrl | string | No | URL to redirect the user after completion |
metadata | object | No | Arbitrary key-value pairs stored with the session |
// Response 201
{
"session": {
"id": "ver_9Xm4pLkWnR",
"organizationId": "org_3Vn9wLkDfT",
"status": "pending",
"level": 2,
"sandbox": false,
"subjectDid": "did:solidus:testnet:7Hk3mRtQZvXp2nBw9Lj4K",
"redirectUrl": "https://acme.com/onboarding/complete",
"metadata": {
"userId": "usr_acme_12345",
"plan": "premium"
},
"sessionToken": "sess_tok_7Hk3mRtQZv...",
"createdAt": "2026-05-07T14:20:00Z",
"expiresAt": "2026-05-07T15:20:00Z"
},
"sessionUrl": "https://verify.solidus.network/v/s/sess_tok_7Hk3mRtQZv..."
}List Sessions
Retrieve all verification sessions for your organization.
GET /verifications
Auth: API Key (x-api-key)
| Query Param | Type | Description |
|---|---|---|
status | string | Filter by status: pending, processing, approved, rejected, expired |
limit | number | Results per page (default: 20, max: 100) |
offset | number | Offset for pagination |
curl "https://verify.solidus.network/v1/verifications?status=approved&limit=10" \
-H "x-api-key: sk_live_abc123def456..."// Response 200
{
"sessions": [
{
"id": "ver_9Xm4pLkWnR",
"status": "approved",
"level": 2,
"subjectDid": "did:solidus:testnet:7Hk3mRtQZvXp2nBw9Lj4K",
"credentialId": "vc_3Kn8rTpXm2",
"createdAt": "2026-05-07T14:20:00Z",
"completedAt": "2026-05-07T14:25:30Z"
}
],
"total": 1
}Get Session
Retrieve a single verification session by ID.
GET /verifications/:id
Auth: API Key (x-api-key)
curl https://verify.solidus.network/v1/verifications/ver_9Xm4pLkWnR \
-H "x-api-key: sk_live_abc123def456..."// Response 200
{
"session": {
"id": "ver_9Xm4pLkWnR",
"organizationId": "org_3Vn9wLkDfT",
"status": "approved",
"level": 2,
"sandbox": false,
"subjectDid": "did:solidus:testnet:7Hk3mRtQZvXp2nBw9Lj4K",
"redirectUrl": "https://acme.com/onboarding/complete",
"metadata": {
"userId": "usr_acme_12345",
"plan": "premium"
},
"documents": [
{
"type": "passport",
"side": "front",
"status": "verified",
"extractedData": {
"firstName": "John",
"lastName": "Doe",
"dateOfBirth": "1990-03-15",
"documentNumber": "AB1234567",
"expiryDate": "2030-06-20",
"nationality": "US"
}
}
],
"liveness": {
"status": "passed",
"score": 0.97,
"completedAt": "2026-05-07T14:24:10Z"
},
"credentialId": "vc_3Kn8rTpXm2",
"createdAt": "2026-05-07T14:20:00Z",
"completedAt": "2026-05-07T14:25:30Z"
}
}Hosted Flow
These endpoints are used by the hosted verification UI. They authenticate with the session token embedded in the URL path rather than an API key.
Get Session by Token
Retrieve the session for the hosted flow.
GET /verifications/s/:sessionToken
Auth: Session token (in URL)
// Response 200
{
"session": {
"id": "ver_9Xm4pLkWnR",
"status": "pending",
"level": 2,
"organizationName": "Acme Corp",
"steps": ["document", "liveness"],
"currentStep": "document",
"expiresAt": "2026-05-07T15:20:00Z"
}
}Upload Document (Hosted)
Upload an identity document for the current session.
POST /verifications/s/:sessionToken/documents
Auth: Session token (in URL)
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | The document image (JPEG or PNG, max 10 MB) |
side | string | Yes | front or back |
type | string | Yes | passport, driving_license, national_id, or residence_permit |
final | boolean | No | If true, marks the document step as complete |
curl -X POST "https://verify.solidus.network/v1/verifications/s/sess_tok_7Hk3mRtQZv.../documents" \
-F "file=@passport_front.jpg" \
-F "side=front" \
-F "type=passport" \
-F "final=true"// Response 201
{
"document": {
"id": "doc_5Wn2kLpMxR",
"type": "passport",
"side": "front",
"status": "uploaded",
"createdAt": "2026-05-07T14:22:00Z"
}
}Get Liveness Challenge (Hosted)
Request a liveness challenge for the session.
GET /verifications/s/:sessionToken/liveness-challenge
Auth: Session token (in URL)
// Response 200
{
"challenge": {
"id": "chl_8Rn3mKpWxT",
"type": "head_turn",
"instructions": "Please turn your head slowly to the left",
"expiresAt": "2026-05-07T14:30:00Z"
}
}Submit Liveness (Hosted)
Submit liveness frames for the challenge.
POST /verifications/s/:sessionToken/liveness
Auth: Session token (in URL)
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
frames | File[] | Yes | Video frames captured during the liveness challenge |
// Response 200
{
"liveness": {
"status": "passed",
"score": 0.97
}
}Document Upload (API Key)
Upload documents and complete liveness checks using your API key instead of the hosted flow.
Upload Document
POST /verifications/:id/documents
Auth: API Key (x-api-key)
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file | File | Yes | The document image (JPEG or PNG, max 10 MB) |
side | string | Yes | front or back |
type | string | Yes | passport, driving_license, national_id, or residence_permit |
final | boolean | No | If true, marks the document step as complete and triggers processing |
curl -X POST "https://verify.solidus.network/v1/verifications/ver_9Xm4pLkWnR/documents" \
-H "x-api-key: sk_live_abc123def456..." \
-F "file=@passport_front.jpg" \
-F "side=front" \
-F "type=passport" \
-F "final=true"// Response 201
{
"document": {
"id": "doc_5Wn2kLpMxR",
"type": "passport",
"side": "front",
"status": "uploaded",
"createdAt": "2026-05-07T14:22:00Z"
}
}Get Liveness Challenge
GET /verifications/:id/liveness-challenge
Auth: API Key (x-api-key)
// Response 200
{
"challenge": {
"id": "chl_8Rn3mKpWxT",
"type": "head_turn",
"instructions": "Please turn your head slowly to the left",
"expiresAt": "2026-05-07T14:30:00Z"
}
}Submit Liveness
POST /verifications/:id/liveness
Auth: API Key (x-api-key)
Content-Type: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
frames | File[] | Yes | Video frames captured during the liveness challenge |
// Response 200
{
"liveness": {
"status": "passed",
"score": 0.97
}
}API Keys
Manage API keys for your organization. Each key is scoped to live or sandbox mode.
Create API Key
POST /api-keys
Auth: JWT Bearer
// Request body
{
"name": "Production Key",
"mode": "live"
}// Response 201
{
"key": "sk_live_abc123def456ghi789jkl012mno345pqr678",
"id": "key_4Tn7mLkPxR"
}The full key is only returned once at creation. Store it securely.
List API Keys
GET /api-keys
Auth: JWT Bearer
// Response 200
{
"keys": [
{
"id": "key_4Tn7mLkPxR",
"name": "Production Key",
"mode": "live",
"prefix": "sk_live_abc123...",
"lastUsedAt": "2026-05-07T14:00:00Z",
"createdAt": "2026-05-01T09:00:00Z"
},
{
"id": "key_6Wn9pMkRxT",
"name": "Test Key",
"mode": "sandbox",
"prefix": "sk_sandbox_xyz789...",
"lastUsedAt": null,
"createdAt": "2026-05-03T11:00:00Z"
}
]
}Delete API Key
DELETE /api-keys/:keyId
Auth: JWT Bearer
curl -X DELETE https://verify.solidus.network/v1/api-keys/key_4Tn7mLkPxR \
-H "Authorization: Bearer eyJhbGciOiJFZERTQSIs..."// Response 200
{
"message": "API key deleted"
}Webhooks
Receive real-time notifications when verification events occur. Webhook payloads are signed with HMAC-SHA256 for verification.
Create Webhook Endpoint
POST /webhooks
Auth: JWT Bearer
// Request body
{
"url": "https://acme.com/webhooks/solidus",
"events": [
"verification.approved",
"verification.rejected",
"verification.expired"
],
"description": "Production webhook for verification results"
}Available events: verification.created, verification.processing, verification.approved, verification.rejected, verification.expired, verification.error.
// Response 201
{
"endpoint": {
"id": "wh_2Kn5mTpLxR",
"url": "https://acme.com/webhooks/solidus",
"events": [
"verification.approved",
"verification.rejected",
"verification.expired"
],
"description": "Production webhook for verification results",
"secret": "whsec_7Hk3mRtQZvXp2nBw9Lj4K...",
"enabled": true,
"createdAt": "2026-05-07T10:00:00Z"
}
}The secret is only returned once. Use it to verify webhook signatures.
List Webhook Endpoints
GET /webhooks
Auth: JWT Bearer
// Response 200
{
"endpoints": [
{
"id": "wh_2Kn5mTpLxR",
"url": "https://acme.com/webhooks/solidus",
"events": ["verification.approved", "verification.rejected", "verification.expired"],
"description": "Production webhook for verification results",
"enabled": true,
"createdAt": "2026-05-07T10:00:00Z"
}
]
}Update Webhook Endpoint
PATCH /webhooks/:endpointId
Auth: JWT Bearer
// Request body
{
"url": "https://acme.com/webhooks/solidus-v2",
"events": ["verification.approved", "verification.rejected"],
"enabled": true
}All fields are optional. Only provided fields are updated.
// Response 200
{
"endpoint": {
"id": "wh_2Kn5mTpLxR",
"url": "https://acme.com/webhooks/solidus-v2",
"events": ["verification.approved", "verification.rejected"],
"description": "Production webhook for verification results",
"enabled": true,
"createdAt": "2026-05-07T10:00:00Z"
}
}Delete Webhook Endpoint
DELETE /webhooks/:endpointId
Auth: JWT Bearer
curl -X DELETE https://verify.solidus.network/v1/webhooks/wh_2Kn5mTpLxR \
-H "Authorization: Bearer eyJhbGciOiJFZERTQSIs..."// Response 200
{
"message": "Webhook endpoint deleted"
}List Webhook Deliveries
View delivery history for a specific endpoint.
GET /webhooks/:endpointId/deliveries
Auth: JWT Bearer
| Query Param | Type | Description |
|---|---|---|
status | string | Filter by status: success, failed, pending |
limit | number | Results per page (default: 20, max: 100) |
offset | number | Offset for pagination |
// Response 200
{
"deliveries": [
{
"id": "dlv_9Xm4pLkWnR",
"event": "verification.approved",
"status": "success",
"statusCode": 200,
"payload": {
"event": "verification.approved",
"data": {
"sessionId": "ver_9Xm4pLkWnR",
"status": "approved",
"credentialId": "vc_3Kn8rTpXm2"
},
"timestamp": "2026-05-07T14:25:30Z"
},
"attemptCount": 1,
"deliveredAt": "2026-05-07T14:25:31Z"
}
],
"total": 1
}