> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veridox.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Document Requests

> Collect documents from external parties with secure, branded upload links.

## 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.

<Info>
  **Key Benefit**: External parties can upload documents through a branded, secure interface without authentication, while you maintain full control and visibility.
</Info>

## How Document Requests Work

Document Requests automate the collection process:

1. **You create a request** with recipient details and expiration date
2. **System sends automated email** with secure upload link to recipient
3. **Recipient uploads files** through branded interface (no account needed)
4. **You monitor progress** and retrieve uploaded files
5. **Analysis happens automatically** once files are uploaded

<Steps>
  <Step title="Create Request">
    Define recipient, expiration, and file limits
  </Step>

  <Step title="Email Sent">
    Automated invitation with secure JWT-protected link
  </Step>

  <Step title="Guest Upload">
    Recipient uploads files without authentication
  </Step>

  <Step title="Analysis">
    Files automatically analysed upon upload
  </Step>

  <Step title="Retrieve Results">
    Access uploaded files and analysis results
  </Step>
</Steps>

## Use Cases

<CardGroup cols={2}>
  <Card title="Insurance Claims" icon="file-invoice">
    Request accident photos, repair estimates, and supporting documents from claimants
  </Card>

  <Card title="Loan Applications" icon="building-columns">
    Collect bank statements, payslips, and tax documents from applicants
  </Card>

  <Card title="Customer Onboarding" icon="user-plus">
    Gather identity documents, proof of address, and compliance paperwork
  </Card>

  <Card title="Vendor Verification" icon="handshake">
    Request business registrations, tax certificates, and director IDs
  </Card>
</CardGroup>

## Creating Document Requests

### Basic Request Creation

Create a document request with essential details:

```javascript theme={null}
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);
```

<Info>
  **API Reference**: See [Create Document Request](/api-reference/endpoints/document-requests-create) for complete documentation.
</Info>

### Request Parameters

| Parameter         | Required | Description                        | Validation               |
| ----------------- | -------- | ---------------------------------- | ------------------------ |
| `label`           | **Yes**  | Descriptive request name           | Max 200 characters       |
| `recipient_email` | **Yes**  | Email address to send invitation   | Valid email format       |
| `expires_at`      | **Yes**  | Request expiration date/time       | ISO 8601, must be future |
| `max_files`       | **Yes**  | Maximum files recipient can upload | 1-20                     |
| `recipient_name`  | No       | Recipient name for personalization | Max 200 characters       |
| `email_message`   | No       | Custom message in email invitation | Max 1000 characters      |

### Setting Expiration Dates

Choose appropriate expiration based on use case:

<Tabs>
  <Tab title="Urgent Requests">
    ```javascript theme={null}
    // 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.'
    });
    ```
  </Tab>

  <Tab title="Standard Requests">
    ```javascript theme={null}
    // 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.'
    });
    ```
  </Tab>

  <Tab title="Extended Requests">
    ```javascript theme={null}
    // 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.'
    });
    ```
  </Tab>
</Tabs>

## Request Lifecycle

### Status Progression

Document requests transition through three states:

<Columns>
  <Col>
    ### Pending

    **Initial state** after creation

    * Email invitation sent
    * Link active and accessible
    * No files uploaded yet
    * Can be accessed multiple times

    **Actions Available**:

    * Resend invitation email
    * Monitor access count
    * Delete request
  </Col>

  <Col>
    ### Completed

    **Final state** when files uploaded

    * Max files reached, or
    * Manually marked complete
    * Link becomes inactive
    * Files available for retrieval

    **Actions Available**:

    * Retrieve uploaded files
    * View analysis results
    * Access audit trail
  </Col>
</Columns>

### 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:

```javascript theme={null}
// 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`);
});
```

<Info>
  **API Reference**: See [List Document Requests](/api-reference/endpoints/document-requests-list) for filtering options.
</Info>

### Get Request Details

Monitor individual request progress:

```javascript theme={null}
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);
}
```

<Info>
  **API Reference**: See [Get Document Request](/api-reference/endpoints/document-requests-get) for complete response schema.
</Info>

### Tracking Metrics

Monitor key metrics for request performance:

```javascript theme={null}
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:

```javascript theme={null}
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');
}
```

<Info>
  **API Reference**: See [Resend Document Request](/api-reference/endpoints/document-requests-resend) for details.
</Info>

**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:

```javascript theme={null}
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');
}
```

<Info>
  **API Reference**: See [Delete Document Request](/api-reference/endpoints/document-requests-delete) for details.
</Info>

**When to Cancel**:

* Request sent to wrong recipient
* Information requirements changed
* Applicant withdrew application
* Duplicate request created by mistake

<Warning>
  **Deletion is Permanent**: Deleting a request also deactivates the upload link immediately. Recipient will no longer be able to access the link.
</Warning>

## Retrieving Uploaded Files

### Accessing Files Through Cases

All uploads are associated with a case for analysis:

```javascript theme={null}
// 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

```javascript theme={null}
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:

<Tabs>
  <Tab title="Insurance Claim">
    ```javascript theme={null}
    {
      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')
    }
    ```
  </Tab>

  <Tab title="Loan Application">
    ```javascript theme={null}
    {
      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')
    }
    ```
  </Tab>

  <Tab title="Customer Onboarding">
    ```javascript theme={null}
    {
      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')
    }
    ```
  </Tab>
</Tabs>

## Automation Patterns

### Automated Request Creation

Create requests automatically from business events:

```javascript theme={null}
// 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:

```javascript theme={null}
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](/guides/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

<Check>**Descriptive labels** - Include identifiers (claim numbers, application IDs) for easy tracking</Check>
<Check>**Clear instructions** - Specify exactly what documents are needed and formatting requirements</Check>
<Check>**Appropriate expiration** - Balance urgency with recipient availability (7-30 days typical)</Check>
<Check>**Realistic file limits** - Consider document types and allow buffer for unexpected files</Check>

### Email Communication

<Check>**Professional tone** - Use clear, respectful language in custom messages</Check>
<Check>**Actionable guidance** - List specific documents needed and acceptance criteria</Check>
<Check>**Contact information** - Provide support contact for questions</Check>
<Check>**Deadline clarity** - Clearly state expiration date and consequences</Check>

### Monitoring and Follow-Up

<Check>**Track access rates** - Monitor if recipients are opening links</Check>
<Check>**Send reminders** - Follow up on pending requests before expiration</Check>
<Check>**Analyse completion rates** - Identify patterns in successful vs. failed requests</Check>
<Check>**Automate workflows** - Create requests automatically from business events</Check>

### Security

<Check>**Validate recipients** - Verify email addresses before sending</Check>
<Check>**Appropriate expiration** - Don't set excessively long expiration periods</Check>
<Check>**Monitor unusual activity** - Watch for suspicious upload patterns</Check>
<Check>**Access control** - Users can only access document requests they have created</Check>
<Check>**Audit access** - Review access counts and timestamps regularly</Check>

## 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 |

<Info>
  **Best Practice**: Cache request data and use pagination to stay within limits. See [Error Handling](/guides/error-handling#rate-limiting-errors-429) for retry strategies.
</Info>

## 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:

```javascript theme={null}
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:

```javascript theme={null}
// 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}`);
});
```

## Related Resources

<CardGroup cols={2}>
  <Card title="Create Request API" icon="plus" href="/api-reference/endpoints/document-requests-create">
    Detailed API reference for creating document requests
  </Card>

  <Card title="List Requests API" icon="list" href="/api-reference/endpoints/document-requests-list">
    Retrieve and filter document requests
  </Card>

  <Card title="Get Request API" icon="file-magnifying-glass" href="/api-reference/endpoints/document-requests-get">
    Get detailed request status and metrics
  </Card>

  <Card title="Resend Invitation API" icon="paper-plane" href="/api-reference/endpoints/document-requests-resend">
    Resend email invitations to recipients
  </Card>

  <Card title="Delete Request API" icon="trash" href="/api-reference/endpoints/document-requests-delete">
    Cancel and delete document requests
  </Card>

  <Card title="Case Management" icon="folder" href="/guides/case-management">
    Understanding cases and file organisation
  </Card>

  <Card title="Document Analysis" icon="file-certificate" href="/guides/document-analysis">
    How uploaded documents are analysed
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Handling API errors and rate limits
  </Card>
</CardGroup>
