Overview
This guide shows you how to verify a government-issued identity document (passport, driver’s license, national ID) using only the Beltic API. This is the fastest path to document verification — no SDK integration, no session management, and no client-side setup required.
You will:
Create a document/idv with file declarations and get presigned upload URLs
Upload the document images to the presigned URLs
After the files are uploaded, the document is automatically processed — a verification is created, authenticity checks are run, and data is extracted from the document.
Prerequisites
A Beltic API key with documents:write and verifications:write permissions
A document image (JPEG or PNG) of a government-issued ID
Step 1: Create the Document
Create a document/idv resource with the files you intend to upload declared in the request body. Since we’re running a standalone verification, we don’t need to link it to a session or account.
curl -X POST https://api.beltic.com/v1/identity/documents/idvs \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "document/idv",
"attributes": {
"files": [
{
"filename": "id_card.jpeg"
}
]
}
}
}'
The response contains the document ID and presigned upload URLs for each declared file:
{
"data" : {
"type" : "document/idv" ,
"id" : "doc_01HQ..." ,
"attributes" : {
"status" : "pending" ,
"document_type" : null ,
"files" : [
{
"id" : "file_01..." ,
"filename" : "id_card.jpeg" ,
"status" : "pending_upload"
}
],
"created_at" : "2025-01-15T10:30:00Z"
}
},
"meta" : {
"files" : [
{
"id" : "file_01..." ,
"presigned_upload_url" : "https://files.beltic.com/doc_01HQ.../id_card.jpeg?X-Amz-Signature=..." ,
"expires_in" : 3600
}
]
}
}
For two-sided documents (like a driver’s license or national ID card), declare both files in the request. This improves extraction accuracy and enables additional security checks. {
"data" : {
"type" : "document/idv" ,
"attributes" : {
"files" : [
{ "filename" : "id_card_front.jpeg" },
{ "filename" : "id_card_back.jpeg" }
]
}
}
}
Step 2: Upload the Document Images
Upload each file to its corresponding presigned URL using a PUT request:
curl -X PUT "{presigned_upload_url}" \
-H "Content-Type: image/jpeg" \
--data-binary @id_card.jpeg
The presigned URL expires after the time specified in expires_in (typically 1 hour). Upload your files before it expires.
Once all files are uploaded, the document is automatically processed — Beltic runs the verification, performs authenticity checks, and extracts identity data from the document. No additional API call is needed.
Retrieving the Results
After uploading, poll the document to check when processing is complete:
curl -X GET https://api.beltic.com/v1/identity/documents/idvs/{document_id} \
-H "X-Api-Key: YOUR_API_KEY"
When the status changes from pending to processed, the document response includes all extracted data and the linked verification with check results:
{
"data" : {
"type" : "document/idv" ,
"id" : "doc_01HQ..." ,
"attributes" : {
"status" : "processed" ,
"document_type" : "passport" ,
"name" : {
"first" : "Jane" ,
"middle" : null ,
"last" : "Doe"
},
"birth_date" : "1990-05-15" ,
"sex" : "female" ,
"document_number" : "AB1234567" ,
"issue_date" : "2020-03-01" ,
"expiry_date" : "2030-03-01" ,
"issuing_authority" : "Department of State" ,
"nationality" : "US" ,
"issuing_country" : "US" ,
"address" : null ,
"front_side" : {
"id" : "file_01..." ,
"filename" : "front_cropped.jpg"
},
"portrait" : {
"id" : "file_02..." ,
"filename" : "portrait.jpg"
},
"back_side" : null ,
"signature" : null ,
"created_at" : "2025-01-15T10:30:00Z" ,
"submitted_at" : "2025-01-15T10:30:05Z" ,
"processed_at" : "2025-01-15T10:30:08Z"
}
}
}
You can also retrieve the verification directly to inspect individual check results:
curl -X GET "https://api.beltic.com/v1/identity/verifications?filter[document_id]=doc_01HQ..." \
-H "X-Api-Key: YOUR_API_KEY"
Verification Response
{
"data" : [
{
"type" : "verification/idv" ,
"id" : "ver_01HQ..." ,
"attributes" : {
"status" : "passed" ,
"capture_method" : "api" ,
"document_type" : "passport" ,
"name" : {
"first" : "Jane" ,
"middle" : null ,
"last" : "Doe"
},
"birth_date" : "1990-05-15" ,
"document_number" : "AB1234567" ,
"expiry_date" : "2030-03-01" ,
"issuing_country" : "US" ,
"checks" : [
{
"name" : "status_optical" ,
"status" : "passed" ,
"requirement" : "required" ,
"reasons" : [],
"metadata" : {}
},
{
"name" : "optical_expiry" ,
"status" : "passed" ,
"requirement" : "required" ,
"reasons" : [],
"metadata" : {}
},
{
"name" : "optical_mrz" ,
"status" : "passed" ,
"requirement" : "required" ,
"reasons" : [],
"metadata" : {}
},
{
"name" : "optical_doc_type" ,
"status" : "passed" ,
"requirement" : "required" ,
"reasons" : [],
"metadata" : {}
},
{
"name" : "image_quality_glare" ,
"status" : "not_applicable" ,
"requirement" : "not_required" ,
"reasons" : [],
"metadata" : {}
}
],
"created_at" : "2025-01-15T10:30:05Z" ,
"completed_at" : "2025-01-15T10:30:08Z"
}
}
]
}
Interpreting Results
Overall Status
Status What it means What to do passedThe document passed all required checks Accept the verification failedOne or more required checks failed Reject or investigate further requires_retryImage quality issues prevented verification Ask the user to retake the photo
Key Checks to Monitor
For most use cases, pay attention to these checks:
status_optical — Was the document successfully read?
optical_expiry — Is the document expired?
optical_mrz — Does the MRZ (machine-readable zone) validate?
optical_security — Do security features check out?
image_quality_* — Was the image quality sufficient?
Handling Failures
const verification = response . data [ 0 ];
const { status , checks } = verification . attributes ;
if ( status === 'passed' ) {
console . log ( 'Document verified successfully' );
console . log ( 'Name:' , verification . attributes . name );
console . log ( 'DOB:' , verification . attributes . birth_date );
console . log ( 'Doc #:' , verification . attributes . document_number );
} else if ( status === 'requires_retry' ) {
const retryChecks = checks . filter ( c => c . requirement === 'requires_retry' );
console . log ( 'Please retake the photo. Issues:' , retryChecks . map ( c => c . name ));
} else if ( status === 'failed' ) {
const failedChecks = checks . filter ( c => c . status === 'failed' );
console . log ( 'Verification failed:' , failedChecks . map ( c => ({
check: c . name ,
reasons: c . reasons
})));
}
Complete Example
Here’s a complete Node.js example that runs a document verification end-to-end:
import fs from 'fs' ;
const API_KEY = 'YOUR_API_KEY' ;
const BASE_URL = 'https://api.beltic.com/v1/identity' ;
async function verifyDocument ( imagePath ) {
const headers = {
'X-Api-Key' : API_KEY ,
'Content-Type' : 'application/json'
};
const filename = imagePath . split ( '/' ). pop ();
// Step 1: Create the document with file declarations
const docResponse = await fetch ( ` ${ BASE_URL } /documents/idvs` , {
method: 'POST' ,
headers ,
body: JSON . stringify ({
data: {
type: 'document/idv' ,
attributes: {
files: [{ filename }]
}
}
})
});
const doc = await docResponse . json ();
const documentId = doc . data . id ;
const uploadUrl = doc . meta . files [ 0 ]. presigned_upload_url ;
console . log ( `Created document: ${ documentId } ` );
// Step 2: Upload the file
await fetch ( uploadUrl , {
method: 'PUT' ,
headers: { 'Content-Type' : 'image/jpeg' },
body: fs . readFileSync ( imagePath )
});
console . log ( 'File uploaded — processing automatically...' );
// Step 3: Poll until processed
let document ;
while ( true ) {
const statusResponse = await fetch ( ` ${ BASE_URL } /documents/idvs/ ${ documentId } ` , {
headers: { 'X-Api-Key' : API_KEY }
});
document = await statusResponse . json ();
const status = document . data . attributes . status ;
if ( status === 'processed' ) {
console . log ( 'Document processed!' );
break ;
} else if ( status === 'failed' ) {
throw new Error ( 'Document processing failed' );
}
console . log ( `Status: ${ status } — waiting...` );
await new Promise ( resolve => setTimeout ( resolve , 3000 ));
}
// Print extracted data
const attrs = document . data . attributes ;
console . log ( `Name: ${ attrs . name ?. first } ${ attrs . name ?. last } ` );
console . log ( `DOB: ${ attrs . birth_date } ` );
console . log ( `Document #: ${ attrs . document_number } ` );
console . log ( `Expiry: ${ attrs . expiry_date } ` );
return document ;
}
// Usage
verifyDocument ( './id_card.jpeg' );
Tips for Best Results
Use high-resolution images (at least 300 DPI)
Ensure even lighting with no glare or shadows
Capture the full document with all edges visible
Place the document on a dark, contrasting background
For documents with information on both sides (e.g., driver’s licenses), declare and upload both images. This enables:
More complete data extraction
Additional security checks
Better overall verification accuracy
The IDV verification engine supports a wide range of government-issued documents:
Passports
Driver’s licenses
National identity cards
Residence permits
Travel documents
And many more
Next Steps