Skip to Content
GuidesKYC Integration

KYC Integration

Embed Solidus KYC verification into your application. Users complete identity verification once and receive a Verifiable Credential they can present anywhere, eliminating repeated KYC processes.

Prerequisites

Integration Modes

Solidus Verify supports two integration patterns:

ModeHow it worksBest for
Hosted flowRedirect users to the Solidus-hosted verification pageFastest integration, no UI work needed
API flowUpload documents directly via API callsCustom UI, mobile apps, embedded experiences

Base URL

All API requests use the following base URL:

https://verify.solidus.network/v1

Authenticate every request with your API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

Hosted Flow

Step 1: Create a Verification Session

const response = await fetch('https://verify.solidus.network/v1/verifications', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY', }, body: JSON.stringify({ // The DID of the user being verified (optional for hosted flow) subjectDid: 'did:solidus:testnet:7Hk3mRtQZv...', // Verification level: 1 = basic (ID + liveness), 2 = enhanced (+ address) level: 1, // Where to redirect after verification completes redirectUrl: 'https://myapp.com/verification-complete', // Webhook to receive status updates webhook: { url: 'https://myapp.com/webhooks/verify', events: ['verification.completed', 'verification.failed'], }, // Optional: pre-fill user information prefill: { firstName: 'Jane', lastName: 'Doe', email: '[email protected]', country: 'US', }, }), }) const session = await response.json()

The response contains the session ID and the URL to redirect the user to:

{ "id": "ver_2xK9mP4qR7nL", "status": "pending", "sessionUrl": "https://verify.solidus.network/session/ver_2xK9mP4qR7nL", "expiresAt": "2026-05-07T13:00:00Z", "createdAt": "2026-05-07T12:00:00Z" }

Step 2: Redirect the User

Send the user to sessionUrl. They will see the Solidus verification interface where they upload documents and complete a liveness check.

// In your frontend window.location.href = session.sessionUrl

Step 3: Handle the Redirect

After verification, the user is redirected to your redirectUrl with the session ID as a query parameter:

https://myapp.com/verification-complete?session=ver_2xK9mP4qR7nL&status=completed

Step 4: Check the Result

Query the session status to get the verification result and issued credential.

const result = await fetch( 'https://verify.solidus.network/v1/verifications/ver_2xK9mP4qR7nL', { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, } ) const verification = await result.json()

The completed verification response:

{ "id": "ver_2xK9mP4qR7nL", "status": "completed", "level": 1, "subjectDid": "did:solidus:testnet:7Hk3mRtQZv...", "result": { "outcome": "pass", "checks": { "documentAuthenticity": "pass", "faceMatch": "pass", "livenessDetection": "pass", "nameMatch": "pass", "ageVerification": "pass" }, "extractedData": { "firstName": "Jane", "lastName": "Doe", "dateOfBirth": "1990-03-15", "documentType": "passport", "documentCountry": "US", "documentNumber": "***redacted***" } }, "credential": { "@context": ["https://www.w3.org/2018/credentials/v1"], "type": ["VerifiableCredential", "KYCCredential"], "issuer": "did:solidus:testnet:verify-service", "credentialSubject": { "id": "did:solidus:testnet:7Hk3mRtQZv...", "level": 1, "country": "US" }, "proof": { "type": "Ed25519Signature2020", "proofValue": "z3FXQ..." } }, "completedAt": "2026-05-07T12:05:30Z", "createdAt": "2026-05-07T12:00:00Z" }

API Flow

Use the API flow when you want full control over the UI. You collect the documents from the user and upload them directly.

Step 1: Create a Session

Same as the hosted flow, but omit redirectUrl:

const response = await fetch('https://verify.solidus.network/v1/verifications', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY', }, body: JSON.stringify({ subjectDid: 'did:solidus:testnet:7Hk3mRtQZv...', level: 1, webhook: { url: 'https://myapp.com/webhooks/verify', events: ['verification.completed', 'verification.failed'], }, }), }) const { id: sessionId } = await response.json()

Step 2: Upload Documents

Upload identity documents to the session. Supported formats: JPEG, PNG, PDF. Maximum file size: 10 MB.

// Upload the front of an identity document const frontUpload = new FormData() frontUpload.append('file', frontImageFile) frontUpload.append('type', 'document_front') await fetch( \`https://verify.solidus.network/v1/verifications/${sessionId}/documents\`, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: frontUpload, } ) // Upload the back of the document (required for ID cards and driver's licenses) const backUpload = new FormData() backUpload.append('file', backImageFile) backUpload.append('type', 'document_back') await fetch( \`https://verify.solidus.network/v1/verifications/${sessionId}/documents\`, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: backUpload, } ) // Upload a selfie for face matching const selfieUpload = new FormData() selfieUpload.append('file', selfieFile) selfieUpload.append('type', 'selfie') await fetch( \`https://verify.solidus.network/v1/verifications/${sessionId}/documents\`, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, body: selfieUpload, } )

Document types:

TypeDescriptionRequired
document_frontFront of passport, ID card, or driver’s licenseAlways
document_backBack of ID card or driver’s licenseID cards and driver’s licenses
selfieUser’s face photo for liveness/face matchingAlways
proof_of_addressUtility bill or bank statementLevel 2 only

Step 3: Submit for Processing

After uploading all documents, submit the session for processing:

await fetch( \`https://verify.solidus.network/v1/verifications/${sessionId}/submit\`, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, } )

Step 4: Receive Results

Results arrive via webhook or polling. See the Webhooks guide for webhook setup. To poll:

let status = 'processing' while (status === 'processing') { const res = await fetch( \`https://verify.solidus.network/v1/verifications/${sessionId}\`, { headers: { 'Authorization': 'Bearer YOUR_API_KEY' }, } ) const data = await res.json() status = data.status if (status === 'processing') { await new Promise((r) => setTimeout(r, 3000)) } }

Webhook Events

Configure webhooks to receive real-time notifications about verification status changes.

EventDescription
verification.completedVerification finished successfully, credential issued
verification.failedVerification failed (document issues, face mismatch, etc.)
verification.expiredSession expired before the user completed verification

Webhook payload example:

{ "id": "evt_8nR3kL5mQ2", "type": "verification.completed", "createdAt": "2026-05-07T12:05:30Z", "data": { "verificationId": "ver_2xK9mP4qR7nL", "status": "completed", "outcome": "pass", "subjectDid": "did:solidus:testnet:7Hk3mRtQZv...", "level": 1, "credentialId": "urn:uuid:credential-id-here" } }

See the Webhooks guide for full details on signature verification and delivery handling.

Sandbox Mode

Use sandbox mode during development to test the full flow without real identity documents.

Set sandbox: true when creating a session. Control the outcome with sandboxOutcome:

const response = await fetch('https://verify.solidus.network/v1/verifications', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer YOUR_API_KEY', }, body: JSON.stringify({ subjectDid: 'did:solidus:testnet:7Hk3mRtQZv...', level: 1, sandbox: true, sandboxOutcome: 'pass', // 'pass', 'fail', or 'error' redirectUrl: 'https://localhost:3000/verification-complete', }), })

Sandbox sessions:

  • Skip real document analysis
  • Complete within seconds
  • Issue test credentials (not valid for production)
  • Support all the same API endpoints and webhooks

Available sandbox outcomes:

OutcomeBehavior
passVerification succeeds, test credential issued
failVerification fails with simulated document issues
errorSimulates a processing error for testing error handling

Verification Statuses

A session moves through these statuses:

pending ──> processing ──> completed ├──> failed └──> expired
StatusDescription
pendingSession created, waiting for user to start
processingDocuments uploaded, verification in progress
completedVerification passed, credential issued
failedVerification failed
expiredSession expired (default: 1 hour)

Error Handling

The API returns standard HTTP status codes with error details:

{ "error": { "code": "invalid_document", "message": "The uploaded document could not be read. Please upload a clear photo.", "details": { "documentType": "document_front", "reason": "blur_detected" } } }

Common error codes:

CodeDescription
invalid_documentDocument image is blurry, cropped, or unreadable
face_mismatchSelfie does not match the document photo
document_expiredThe identity document has expired
unsupported_documentDocument type or country not supported
session_expiredVerification session has expired
rate_limit_exceededToo many requests (limit: 100 requests/minute)

Next Steps

Last updated on