Skip to Content
API ReferenceVerify API

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" } }
FieldTypeRequiredDescription
level1 | 2 | 3YesVerification level. 1 = document only, 2 = document + liveness, 3 = document + liveness + address proof
sandboxbooleanNoIf true, runs in sandbox mode with no real verification
sandboxOutcomestringNoForce a sandbox result: "approved", "rejected", "error"
subjectDidstringNoAssociate the session with a specific DID
redirectUrlstringNoURL to redirect the user after completion
metadataobjectNoArbitrary 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 ParamTypeDescription
statusstringFilter by status: pending, processing, approved, rejected, expired
limitnumberResults per page (default: 20, max: 100)
offsetnumberOffset 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

FieldTypeRequiredDescription
fileFileYesThe document image (JPEG or PNG, max 10 MB)
sidestringYesfront or back
typestringYespassport, driving_license, national_id, or residence_permit
finalbooleanNoIf 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

FieldTypeRequiredDescription
framesFile[]YesVideo 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

FieldTypeRequiredDescription
fileFileYesThe document image (JPEG or PNG, max 10 MB)
sidestringYesfront or back
typestringYespassport, driving_license, national_id, or residence_permit
finalbooleanNoIf 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

FieldTypeRequiredDescription
framesFile[]YesVideo 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 ParamTypeDescription
statusstringFilter by status: success, failed, pending
limitnumberResults per page (default: 20, max: 100)
offsetnumberOffset 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 }
Last updated on