Overview
Document Requests enable you to collect files from external parties (customers, applicants, claimants) without requiring them to create an account. This feature streamlines document collection workflows by sending secure, time-limited upload links via email.
Key Benefit : External parties can upload documents through a branded, secure interface without authentication, while you maintain full control and visibility.
How Document Requests Work
Document Requests automate the collection process:
You create a request with recipient details and expiration date
System sends automated email with secure upload link to recipient
Recipient uploads files through branded interface (no account needed)
You monitor progress and retrieve uploaded files
Analysis happens automatically once files are uploaded
Create Request
Define recipient, expiration, and file limits
Email Sent
Automated invitation with secure JWT-protected link
Guest Upload
Recipient uploads files without authentication
Analysis
Files automatically analysed upon upload
Retrieve Results
Access uploaded files and analysis results
Use Cases
Insurance Claims Request accident photos, repair estimates, and supporting documents from claimants
Loan Applications Collect bank statements, payslips, and tax documents from applicants
Customer Onboarding Gather identity documents, proof of address, and compliance paperwork
Vendor Verification Request business registrations, tax certificates, and director IDs
Creating Document Requests
Basic Request Creation
Create a document request with essential details:
const response = await fetch ( 'https://api.{region}.veridox.ai/document-requests/create' , {
method: 'POST' ,
headers: {
'X-API-Key' : 'vdx_your_api_key' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
label: 'Insurance Claim #CLM-2026-001' ,
recipient_email: 'customer@email.com' ,
recipient_name: 'John Smith' ,
expires_at: '2026-02-15T23:59:59.000Z' ,
max_files: 10 ,
email_message: 'Please upload photos of the damage, repair estimates, and any witness statements.'
})
});
const request = await response . json ();
console . log ( 'Request created:' , request . id );
console . log ( 'Associated case:' , request . case_id );
Request Parameters
Parameter Required Description Validation labelYes Descriptive request name Max 200 characters recipient_emailYes Email address to send invitation Valid email format expires_atYes Request expiration date/time ISO 8601, must be future max_filesYes Maximum files recipient can upload 1-20 recipient_nameNo Recipient name for personalization Max 200 characters email_messageNo Custom message in email invitation Max 1000 characters
Setting Expiration Dates
Choose appropriate expiration based on use case:
Urgent Requests
Standard Requests
Extended Requests
// 48 hours for urgent claims
const expiresAt = new Date ();
expiresAt . setHours ( expiresAt . getHours () + 48 );
const request = await createDocumentRequest ({
label: 'Urgent: Accident Claim Evidence' ,
recipient_email: 'claimant@insurance.com' ,
expires_at: expiresAt . toISOString (),
max_files: 5 ,
email_message: 'URGENT: Please upload accident photos within 48 hours.'
});
// 14 days for standard document collection
const expiresAt = new Date ();
expiresAt . setDate ( expiresAt . getDate () + 14 );
const request = await createDocumentRequest ({
label: 'Loan Application Documents' ,
recipient_email: 'applicant@bank.com' ,
expires_at: expiresAt . toISOString (),
max_files: 15 ,
email_message: 'Please upload your bank statements, payslips, and tax returns.'
});
// 30 days for comprehensive document packages
const expiresAt = new Date ();
expiresAt . setDate ( expiresAt . getDate () + 30 );
const request = await createDocumentRequest ({
label: 'Business Verification Package' ,
recipient_email: 'vendor@company.com' ,
expires_at: expiresAt . toISOString (),
max_files: 20 ,
email_message: 'Please upload all business registration and compliance documents.'
});
Request Lifecycle
Status Progression
Document requests transition through three states:
Expired State
Automatic expiration when time limit reached:
Link becomes inactive
No uploads possible
Request marked as expired
Can create new request if needed
Monitoring Requests
List All Requests
Retrieve requests with filtering and pagination:
// Get all pending requests belonging to you
const response = await fetch (
'https://api.{region}.veridox.ai/document-requests?status=pending&limit=20' ,
{
headers: { 'X-API-Key' : 'vdx_your_api_key' }
}
);
const { links , total } = await response . json ();
console . log ( `Total pending requests: ${ total } ` );
links . forEach ( request => {
console . log ( ` ${ request . label } : ${ request . uploaded_files_count } / ${ request . max_files } files` );
console . log ( ` Expires: ${ new Date ( request . expires_at ). toLocaleDateString () } ` );
console . log ( ` Accessed: ${ request . access_count } times` );
});
Get Request Details
Monitor individual request progress:
const requestId = '019c003f-3c82-72a2-99b6-267e331692c0' ;
const response = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } ` ,
{
headers: { 'X-API-Key' : 'vdx_your_api_key' }
}
);
const request = await response . json ();
console . log ( 'Status:' , request . status );
console . log ( 'Files uploaded:' , request . uploaded_files_count );
console . log ( 'Last accessed:' , request . last_accessed_at );
if ( request . completed_at ) {
console . log ( 'Completed at:' , request . completed_at );
}
Tracking Metrics
Monitor key metrics for request performance:
async function getRequestMetrics ( requests ) {
return requests . reduce (( metrics , request ) => {
// Completion rate
if ( request . status === 'completed' ) {
metrics . completed ++ ;
}
// Access rate (recipient opened link)
if ( request . access_count > 0 ) {
metrics . accessed ++ ;
}
// Upload rate (at least one file uploaded)
if ( request . uploaded_files_count > 0 ) {
metrics . uploaded ++ ;
}
// Expiration without completion
if ( request . status === 'expired' && request . uploaded_files_count === 0 ) {
metrics . expired_unused ++ ;
}
return metrics ;
}, {
completed: 0 ,
accessed: 0 ,
uploaded: 0 ,
expired_unused: 0
});
}
// Usage
const allRequests = await fetchAllRequests ();
const metrics = getRequestMetrics ( allRequests );
console . log ( 'Completion rate:' , ( metrics . completed / allRequests . length * 100 ). toFixed ( 1 ) + '%' );
console . log ( 'Access rate:' , ( metrics . accessed / allRequests . length * 100 ). toFixed ( 1 ) + '%' );
console . log ( 'Upload rate:' , ( metrics . uploaded / allRequests . length * 100 ). toFixed ( 1 ) + '%' );
Managing Requests
Resending Invitations
Resend invitation email if recipient didn’t receive original:
const requestId = '019c003f-3c82-72a2-99b6-267e331692c0' ;
const response = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } /resend` ,
{
method: 'POST' ,
headers: {
'X-API-Key' : 'vdx_your_api_key' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
email_message: 'Resending: Please upload the required documents for your claim.'
})
}
);
if ( response . ok ) {
console . log ( 'Invitation resent successfully' );
}
When to Resend :
Recipient reports not receiving email (check spam folders first)
Original email expired or deleted
Need to update custom message with additional instructions
Following up on pending requests
Canceling Requests
Delete requests that are no longer needed:
const requestId = '019c003f-3c82-72a2-99b6-267e331692c0' ;
const response = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } ` ,
{
method: 'DELETE' ,
headers: { 'X-API-Key' : 'vdx_your_api_key' }
}
);
if ( response . ok ) {
console . log ( 'Request deleted successfully' );
}
When to Cancel :
Request sent to wrong recipient
Information requirements changed
Applicant withdrew application
Duplicate request created by mistake
Deletion is Permanent : Deleting a request also deactivates the upload link immediately. Recipient will no longer be able to access the link.
Retrieving Uploaded Files
Accessing Files Through Cases
All uploads are associated with a case for analysis:
// Get request details to find case ID
const request = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
// Get case details with uploaded files
const caseData = await fetch (
`https://api.{region}.veridox.ai/cases/ ${ request . case_id } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
console . log ( 'Case files:' , caseData . files . length );
// Access each file's analysis
for ( const file of caseData . files ) {
console . log ( `File: ${ file . label } ` );
console . log ( ` Risk: ${ file . current_risk_score || 'pending' } ` );
console . log ( ` Status: ${ file . analysis_status } ` );
}
Complete Retrieval Workflow
async function processDocumentRequestUploads ( requestId ) {
// 1. Get request details
const request = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
if ( request . status !== 'completed' ) {
console . log ( 'Request not yet completed' );
return ;
}
// 2. Get associated case
const caseData = await fetch (
`https://api.{region}.veridox.ai/cases/ ${ request . case_id } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
console . log ( `Processing ${ caseData . files . length } uploaded files` );
// 3. Get detailed analysis for each file
const analyses = await Promise . all (
caseData . files . map ( file =>
fetch (
`https://api.{region}.veridox.ai/files/ ${ file . file_id } /analysis` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ())
)
);
// 4. Process results
const results = analyses . map (( analysis , index ) => ({
file: caseData . files [ index ],
riskScore: analysis . current_risk_score ,
summary: analysis . analysis_results ?. full_analysis ?. summary ,
findings: analysis . analysis_results ?. full_analysis ?. findings || []
}));
return results ;
}
// Usage
const results = await processDocumentRequestUploads ( requestId );
results . forEach (({ file , riskScore , summary }) => {
console . log ( ` \n ${ file . label } :` );
console . log ( ` Risk: ${ riskScore } ` );
console . log ( ` ${ summary } ` );
});
Email Invitation
Email Content
Recipients receive a professional email containing:
Subject : Customised with your label (e.g., “Document Request: Insurance Claim #CLM-2026-001”)
Recipient Name : Personalised greeting (if name provided)
Custom Message : Your specific instructions
Upload Link : Secure JWT-protected URL
Expiration Notice : Clear deadline
Support Contact : Help information
Email Customization
Provide clear, actionable instructions:
Insurance Claim
Loan Application
Customer Onboarding
{
label : 'Car Accident Claim - POL-2026-001' ,
recipient_email : 'customer@insurance.com' ,
recipient_name : 'Sarah Johnson' ,
email_message : `Please upload the following documents for your claim:
1. Photos of vehicle damage (all angles)
2. Repair estimate from approved mechanic
3. Police report (if applicable)
4. Witness statements (if available)
If you have questions, contact your claims adjuster at claims@insurance.com.` ,
max_files : 15 ,
expires_at : expiresIn ( 14 , 'days' )
}
{
label : 'Mortgage Pre-Approval Documents' ,
recipient_email : 'applicant@gmail.com' ,
recipient_name : 'Michael Chen' ,
email_message : `To complete your mortgage pre-approval, please upload:
• Last 2 months of bank statements
• Most recent 2 pay stubs
• Last 2 years of tax returns (W-2 or 1099)
• Photo ID (driver's license or passport)
All documents must be clear and complete. Contact your loan officer at loans@bank.com with questions.` ,
max_files : 20 ,
expires_at : expiresIn ( 30 , 'days' )
}
{
label : 'New Account Verification - ACC-123456' ,
recipient_email : 'newcustomer@company.com' ,
recipient_name : 'Emma Wilson' ,
email_message : `Welcome! Please upload these documents to complete account setup:
✓ Government-issued photo ID
✓ Proof of address (utility bill or bank statement, within 3 months)
Your documents will be securely reviewed within 24 hours. Questions? Email support@company.com.` ,
max_files : 3 ,
expires_at : expiresIn ( 7 , 'days' )
}
Automation Patterns
Automated Request Creation
Create requests automatically from business events:
// Example: Create request when insurance claim is filed
async function handleNewClaim ( claim ) {
const expiresAt = new Date ();
expiresAt . setDate ( expiresAt . getDate () + 14 );
const request = await fetch ( 'https://api.{region}.veridox.ai/document-requests/create' , {
method: 'POST' ,
headers: {
'X-API-Key' : process . env . VERIDOX_API_KEY ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
label: `Insurance Claim ${ claim . claimNumber } ` ,
recipient_email: claim . customerEmail ,
recipient_name: claim . customerName ,
expires_at: expiresAt . toISOString (),
max_files: 10 ,
email_message: `Please upload all documentation related to claim ${ claim . claimNumber } . Include damage photos, repair estimates, and any police reports.`
})
}). then ( r => r . json ());
// Store request ID with claim record
await database . claims . update ( claim . id , {
documentRequestId: request . id ,
documentRequestStatus: 'pending'
});
return request ;
}
Follow-Up Reminders
Send reminders for pending requests:
async function sendReminders () {
// Get pending requests expiring soon
const requests = await fetch (
'https://api.{region}.veridox.ai/document-requests?status=pending' ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
const now = new Date ();
const threeDaysFromNow = new Date ( now . getTime () + 3 * 24 * 60 * 60 * 1000 );
for ( const request of requests . links ) {
const expiresAt = new Date ( request . expires_at );
// Send reminder if expiring in 3 days and no uploads yet
if ( expiresAt <= threeDaysFromNow && request . uploaded_files_count === 0 ) {
await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ request . id } /resend` ,
{
method: 'POST' ,
headers: {
'X-API-Key' : apiKey ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
email_message: `REMINDER: Your document upload link expires in 3 days. Please upload the required documents as soon as possible.`
})
}
);
console . log ( `Reminder sent for request: ${ request . label } ` );
}
}
}
// Run daily
setInterval ( sendReminders , 24 * 60 * 60 * 1000 );
Webhooks Integration
You can use webhooks to receive automatic notifications when document request events occur, such as a request being completed. This enables automated workflows like risk-based escalation and auto-approval.
Best Practices
Request Creation
Descriptive labels - Include identifiers (claim numbers, application IDs) for easy tracking
Clear instructions - Specify exactly what documents are needed and formatting requirements
Appropriate expiration - Balance urgency with recipient availability (7-30 days typical)
Realistic file limits - Consider document types and allow buffer for unexpected files
Email Communication
Professional tone - Use clear, respectful language in custom messages
Actionable guidance - List specific documents needed and acceptance criteria
Contact information - Provide support contact for questions
Deadline clarity - Clearly state expiration date and consequences
Monitoring and Follow-Up
Track access rates - Monitor if recipients are opening links
Send reminders - Follow up on pending requests before expiration
Analyse completion rates - Identify patterns in successful vs. failed requests
Automate workflows - Create requests automatically from business events
Security
Validate recipients - Verify email addresses before sending
Appropriate expiration - Don’t set excessively long expiration periods
Monitor unusual activity - Watch for suspicious upload patterns
Access control - Users can only access document requests they have created
Audit access - Review access counts and timestamps regularly
Rate Limits
Document request operations are rate-limited:
Operation Limit Scope Window Create request 10 requests Per IP address Per minute List requests 30 requests Per IP address Per minute Get request details 60 requests Per organisation Per minute Resend invitation 5 requests Per IP address Per minute
Best Practice : Cache request data and use pagination to stay within limits. See Error Handling for retry strategies.
Common Issues
Email Not Received
Problem : Recipient reports not receiving invitation email
Solutions :
Check spam/junk folders
Verify email address is correct
Resend invitation
Check email service provider’s spam filters
Whitelist Veridox sending domain
Link Expired
Problem : Recipient tries to access expired link
Solutions :
Create new document request with updated expiration
Consider longer expiration periods for future requests
Set up automated reminder emails before expiration
Upload Limit Reached
Problem : Recipient needs to upload more files than max_files allows
Solutions :
Delete request and create new one with higher limit
Request recipient to combine documents (e.g., multi-page PDF)
Create second request for additional documents
Files Not Analysed
Problem : Uploaded files not showing analysis results
Solutions :
Check case analysis status via progress endpoints
Large files may take 3-5 minutes to analyse
Verify files are supported formats (PDF, JPEG, PNG)
Contact support if analysis exceeds 10 minutes
Troubleshooting
Request Status Not Updating
Check request details to verify current state:
const request = await fetch (
`https://api.{region}.veridox.ai/document-requests/ ${ requestId } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
console . log ( 'Status:' , request . status );
console . log ( 'Files uploaded:' , request . uploaded_files_count );
console . log ( 'Last updated:' , request . updated_at );
Recipient Upload Failures
Common causes and solutions:
Issue Cause Solution Link won’t open Expired or deleted request Create new request File upload fails File too large (>20 MB) Request smaller file or PDF Max files reached Limit exceeded Delete request, create with higher limit JWT token invalid Link tampered with Resend original invitation
Analysis Not Completing
Monitor case analysis progress:
// Check if analysis is still processing
const caseData = await fetch (
`https://api.{region}.veridox.ai/cases/ ${ request . case_id } ` ,
{ headers: { 'X-API-Key' : apiKey } }
). then ( r => r . json ());
caseData . files . forEach ( file => {
console . log ( ` ${ file . label } : ${ file . analysis_status } ` );
});
Create Request API Detailed API reference for creating document requests
List Requests API Retrieve and filter document requests
Get Request API Get detailed request status and metrics
Resend Invitation API Resend email invitations to recipients
Delete Request API Cancel and delete document requests
Case Management Understanding cases and file organisation
Document Analysis How uploaded documents are analysed
Error Handling Handling API errors and rate limits