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

# Document Verification

Extract and verify data from identity documents, proof of address, company charters, tax certificates, and bank ownership documents using AI-powered document processing.

## Overview

The document verification endpoints use AI (LLM) to extract structured data from uploaded document images. Supported document types:

* **ID Documents**: Passports, national IDs, driver's licenses
* **Proof of Address**: Utility bills, bank statements, government letters
* **Company Charters**: Corporate registration documents
* **Tax Certificates**: Tax registrations, RUC/RFC/VAT/TIN certificates, and equivalent documents
* **Bank Ownership**: Bank account ownership verification documents

## Endpoints

| Document Type    | Endpoint                               | Description                                 |
| ---------------- | -------------------------------------- | ------------------------------------------- |
| ID Document      | `POST /kyc/documents/id`               | Extract data from ID documents              |
| Proof of Address | `POST /kyc/documents/proof-of-address` | Extract data from address proof documents   |
| Company Charter  | `POST /kyc/documents/company-charter`  | Extract data from company charter documents |
| Tax Certificate  | `POST /kyc/documents/tax-certificate`  | Extract tax registration and taxpayer data  |
| Bank Ownership   | `POST /kyc/documents/bank-ownership`   | Extract data from bank ownership documents  |

## Authentication

Requires `kyc:create` permission. Include your Bearer token in the Authorization header.

## Request Body Parameters

<ParamFields>
  <ParamField name="images" type="array" required description="Array of document image objects">
    <ParamField name="data" type="string" required description="Base64-encoded image data" />

    <ParamField name="mime_type" type="string" required description="MIME type: 'image/jpeg', 'image/png', 'application/pdf'" />
  </ParamField>

  <ParamField name="provider" type="string" description="LLM provider: 'bedrock' (default) or 'openai'" />

  <ParamField name="model" type="string" description="Model identifier (for OpenAI provider)" />

  <ParamField name="data_retention" type="string" description="Set to 'ephemeral' for a zero-retention extraction. Equivalent to the X-Data-Retention: ephemeral header." />
</ParamFields>

## Supported Image Formats

* **JPEG** (`image/jpeg`)
* **PNG** (`image/png`)
* **PDF** (`application/pdf`)

## Zero Data Retention (ephemeral mode)

You can request ephemeral processing with either the `X-Data-Retention: ephemeral` header or `"data_retention": "ephemeral"` in the JSON body. Per-request ephemeral must be enabled for your account first: the endpoint identifier `documents.extract` (or the wildcard `*`) has to appear in your tenant's `data_processing_config.allowed_ephemeral_endpoints`, otherwise the request is rejected with a `400`. Tenants can also opt in account-wide by setting `data_processing_config.mode` to `ephemeral` — the tenant-level setting always wins over per-request flags and does not require the allowlist. Contact support to enable either option on your account.

When ephemeral mode is active, the API returns the normal extraction response but never emits the detailed audit event (which otherwise archives the submitted document images and every extracted field). The platform retains only an aggregate billing metric (one counted document verification, with no document content or extracted-field references); tenants with `retain_billing_metrics: false` suppress that too.

Restrictions in ephemeral mode:

* Images must be submitted inline as base64. S3-referenced documents are rejected with `400 ZDR_UNSUPPORTED_IMAGE_FORMAT`, because a document already stored in a durable bucket cannot honor zero retention.

Document extraction queries third-party providers: the document images are sent to the configured LLM (AWS Bedrock or OpenAI) and, for ID documents, to AWS Textract, which process them under their own no-retention / non-training policies. Ephemeral mode guarantees zero retention in Legaltalent's own stores.

## Request Example

### ID Document

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/documents/id \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "images": [
      {
        "data": "base64_encoded_image_data...",
        "mime_type": "image/jpeg"
      }
    ]
  }'
```

### Proof of Address

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/documents/proof-of-address \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "images": [
      {
        "data": "base64_encoded_image_data...",
        "mime_type": "application/pdf"
      }
    ]
  }'
```

### Tax Certificate

```bash theme={null}
curl -X POST https://stg.kyc.legaltalent.ai/kyc/documents/tax-certificate \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "images": [
      {
        "data": "base64_encoded_image_data...",
        "mime_type": "application/pdf"
      }
    ]
  }'
```

## Response Format

### Success Response - ID Document

```json theme={null}
{
  "status": "success",
  "verification_id": "550e8400-e29b-41d4-a716-446655440000",
  "document_type": "id_document",
  "extracted_data": {
    "full_name": "John Doe",
    "document_number": "AB1234567",
    "document_type": "Passport",
    "nationality": "US",
    "date_of_birth": "1985-03-15",
    "expiry_date": "2030-03-15",
    "issue_date": "2020-03-15",
    "issuing_authority": "United States Department of State"
  },
  "confidence_scores": {
    "overall": 0.95,
    "full_name": 0.98,
    "document_number": 0.99,
    "date_of_birth": 0.97
  },
  "processing_time_ms": 3200,
  "timestamp": "2024-11-22T10:30:00Z"
}
```

### Success Response - Proof of Address

```json theme={null}
{
  "status": "success",
  "verification_id": "660e8400-e29b-41d4-a716-446655440001",
  "document_type": "proof_of_address",
  "extracted_data": {
    "address": "123 Main Street, Apt 4B",
    "city": "New York",
    "state": "NY",
    "postal_code": "10001",
    "country": "US",
    "document_date": "2024-10-15",
    "utility_type": "Electric Bill",
    "account_holder_name": "John Doe"
  },
  "confidence_scores": {
    "overall": 0.92,
    "address": 0.95,
    "document_date": 0.90
  },
  "processing_time_ms": 2800,
  "timestamp": "2024-11-22T10:30:00Z"
}
```

### Success Response - Company Charter

```json theme={null}
{
  "status": "success",
  "verification_id": "770e8400-e29b-41d4-a716-446655440002",
  "document_type": "company_charter",
  "extracted_data": {
    "company_name": "Example Corp",
    "registration_number": "12345678",
    "incorporation_date": "2020-01-15",
    "registered_address": "456 Business Ave, Suite 100",
    "city": "San Francisco",
    "state": "CA",
    "country": "US",
    "legal_form": "Corporation",
    "authorized_capital": "1000000",
    "directors": [
      {
        "name": "John Doe",
        "role": "CEO"
      }
    ]
  },
  "confidence_scores": {
    "overall": 0.88,
    "company_name": 0.95,
    "registration_number": 0.92
  },
  "processing_time_ms": 4500,
  "timestamp": "2024-11-22T10:30:00Z"
}
```

### Success Response - Bank Ownership

```json theme={null}
{
  "status": "success",
  "verification_id": "880e8400-e29b-41d4-a716-446655440003",
  "document_type": "bank_ownership",
  "extracted_data": {
    "account_holder_name": "John Doe",
    "account_number": "****1234",
    "bank_name": "Example Bank",
    "account_type": "Checking",
    "routing_number": "123456789",
    "statement_date": "2024-10-31",
    "address": "123 Main Street, New York, NY 10001"
  },
  "confidence_scores": {
    "overall": 0.90,
    "account_holder_name": 0.94,
    "bank_name": 0.92
  },
  "processing_time_ms": 3500,
  "timestamp": "2024-11-22T10:30:00Z"
}
```

### Success Response - Tax Certificate

The following example represents a Uruguayan DGI certificate. Values vary by country and by the content printed on the document.

```json theme={null}
{
  "verification_id": "990e8400-e29b-41d4-a716-446655440004",
  "document_type": "tax_certificate",
  "status": "extracted",
  "extracted_fields": {
    "is_valid_document": true,
    "detected_document_type": "tax_certificate",
    "validation_reason": "Valid DGI tax certificate with RUT and taxpayer information",
    "tax_id": "219999990012",
    "legal_name": "EMPRESA EJEMPLO S.A.",
    "issue_date": "2026-07-01",
    "jurisdiction": "Dirección General Impositiva",
    "document_country": "UY",
    "tax_status": "ACTIVO",
    "address": "AV. EJEMPLO 1234, MONTEVIDEO",
    "legal_form": "SOCIEDAD ANÓNIMA",
    "taxpayer_segment": "NO CEDE",
    "economic_activities": [
      {
        "code": "620100",
        "description": "Actividades de programación informática",
        "is_primary": true
      }
    ],
    "tax_obligations": [
      {
        "name": "IVA",
        "start_date": "2020-01"
      }
    ],
    "image_quality": "good"
  },
  "validations": {
    "document_consistency": "consistent"
  },
  "confidence_scores": {
    "overall": 0.9,
    "llm_extraction": 0.9
  },
  "issues": [],
  "error_message": null,
  "processing_time_ms": 3100,
  "created_at": "2026-07-30T14:30:00+00:00"
}
```

## Response Fields

| Field                | Type           | Description                                                                                |
| -------------------- | -------------- | ------------------------------------------------------------------------------------------ |
| `status`             | string         | Extraction status: `extracted` or `error`                                                  |
| `verification_id`    | string         | Unique identifier for this verification                                                    |
| `document_type`      | string         | Type of document processed                                                                 |
| `extracted_fields`   | object         | Extracted structured data (varies by document type); fields with `null` values are omitted |
| `validations`        | object         | Technical validation results applicable to the document type                               |
| `confidence_scores`  | object         | Confidence scores for extracted fields                                                     |
| `issues`             | array          | Extraction warnings or issues; empty when none were reported                               |
| `error_message`      | string or null | Generic extraction error when `status` is `error`                                          |
| `processing_time_ms` | integer        | Total processing time in milliseconds                                                      |
| `created_at`         | string         | ISO 8601 timestamp of the extraction                                                       |

## Extracted Data Fields

### ID Document Fields

| Field               | Type   | Description                                                                                                                               |
| ------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `full_name`         | string | Full name from document                                                                                                                   |
| `document_number`   | string | Document ID number                                                                                                                        |
| `document_type`     | string | Type of ID (Passport, Driver's License, etc.)                                                                                             |
| `nationality`       | string | Nationality/country code                                                                                                                  |
| `date_of_birth`     | string | Date of birth (YYYY-MM-DD)                                                                                                                |
| `expiry_date`       | string | Expiry date (YYYY-MM-DD)                                                                                                                  |
| `issue_date`        | string | Issue date (YYYY-MM-DD)                                                                                                                   |
| `issuing_authority` | string | Authority that issued the document                                                                                                        |
| `issuing_country`   | string | Country that issued the document (ISO 3166-1 alpha-2)                                                                                     |
| `address`           | string | Domicile address, when the document prints one (e.g. the reverse of the Argentine DNI). Empty for documents that do not carry an address. |

<Note>
  **ID documents used as proof of address.** Some identity documents print the holder's domicile (notably the reverse of the Argentine DNI), which is accepted in lieu of a separate proof of address. When such a document is captured **with its back/reverse side**, the `address` field is populated and the document's issuing country is used as the country of residence in the curated `extracted` block of session webhooks. See [`residence_country` resolution](/api-reference/webhooks/sessions#how-residence-country-is-resolved).
</Note>

### Proof of Address Fields

| Field                 | Type   | Description                     |
| --------------------- | ------ | ------------------------------- |
| `address`             | string | Full address                    |
| `city`                | string | City name                       |
| `state`               | string | State/province                  |
| `postal_code`         | string | Postal/ZIP code                 |
| `country`             | string | Country code                    |
| `document_date`       | string | Date on document (YYYY-MM-DD)   |
| `utility_type`        | string | Type of utility (if applicable) |
| `account_holder_name` | string | Name on the account             |

### Company Charter Fields

| Field                 | Type   | Description                         |
| --------------------- | ------ | ----------------------------------- |
| `company_name`        | string | Registered company name             |
| `registration_number` | string | Company registration number         |
| `incorporation_date`  | string | Date of incorporation (YYYY-MM-DD)  |
| `registered_address`  | string | Registered business address         |
| `city`                | string | City                                |
| `state`               | string | State/province                      |
| `country`             | string | Country code                        |
| `legal_form`          | string | Legal form (Corporation, LLC, etc.) |
| `authorized_capital`  | string | Authorized capital amount           |
| `directors`           | array  | Array of director objects           |

### Tax Certificate Fields

All extraction fields are optional. Fields for which no value was found are omitted from the response.

| Field                    | Type    | Description                                                                                                                                                                      | Example                                                                          |
| ------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `is_valid_document`      | boolean | Whether the image was classified as a tax certificate or tax registration document. It does not prove authenticity or confirm that the taxpayer registration is currently valid. | `true`                                                                           |
| `detected_document_type` | string  | Document type detected in the uploaded image.                                                                                                                                    | `tax_certificate`, `tax_registration`                                            |
| `validation_reason`      | string  | Human-readable reason for the document-type classification.                                                                                                                      | `Valid DGI tax certificate with RUT`                                             |
| `tax_id`                 | string  | Tax identifier as extracted, including formatting printed on the document.                                                                                                       | `219999990012`, `30-71944642-2`                                                  |
| `legal_name`             | string  | Registered legal name shown on the document.                                                                                                                                     | `EMPRESA EJEMPLO S.A.`                                                           |
| `issue_date`             | string  | Document issue date, normally returned as `YYYY-MM-DD`. This field does not establish an expiration date.                                                                        | `2026-07-01`                                                                     |
| `jurisdiction`           | string  | Tax authority or jurisdiction shown or identified from the document.                                                                                                             | `Dirección General Impositiva`                                                   |
| `document_country`       | string  | Tax jurisdiction country normalized to ISO 3166-1 alpha-2.                                                                                                                       | `UY`                                                                             |
| `tax_status`             | string  | Free-text tax status extracted from the document. This field is not a normalized enum. Wording and language may vary.                                                            | `ACTIVO`, `INACTIVO`, `SUSPENDIDO`                                               |
| `address`                | string  | Registered tax address shown on the document.                                                                                                                                    | `AV. EJEMPLO 1234, MONTEVIDEO`                                                   |
| `legal_form`             | string  | Legal form as stated on the document. `null` or omitted for individuals or when not stated.                                                                                      | `SOCIEDAD ANÓNIMA`, `SA`, `SRL`, `LLC`                                           |
| `taxpayer_segment`       | string  | Taxpayer classification as printed by the tax authority. It is not a normalized enum and must not be confused with tax obligations.                                              | `CEDE`, `NO CEDE`, `GRANDES CONTRIBUYENTES`                                      |
| `economic_activities`    | array   | Registered business activities. Each item can include `code`, `description`, and `is_primary`.                                                                                   | `[{"code":"620100","description":"Programación informática","is_primary":true}]` |
| `tax_obligations`        | array   | Taxes, regimes, or obligations. Each item contains `name` and may include `start_date` as `YYYY-MM-DD` or `YYYY-MM`.                                                             | `[{"name":"IVA","start_date":"2020-01"}]`                                        |
| `image_quality`          | string  | Image quality assessment.                                                                                                                                                        | `excellent`, `good`, `acceptable`, `poor`                                        |

<Warning>
  `is_valid_document: true` only means that the uploaded image matches the expected document category. It does not validate the issuer, detect every possible forgery, query the tax authority, or establish that the taxpayer remains active. Use `tax_status` as extracted evidence and perform an authoritative registry check when current legal or tax status is required.
</Warning>

`tax_status`, `legal_form`, and `taxpayer_segment` currently preserve free-text document values rather than returning canonical enums. Integrations should preserve unknown values and avoid rejecting responses solely because a new label appears.

There is no default validity period calculated from `issue_date`. A workflow can enforce its own age policy with [`max_days_since_issue`](/api-reference/workflows/automations#document-rules).

### Bank Ownership Fields

| Field                 | Type   | Description                               |
| --------------------- | ------ | ----------------------------------------- |
| `account_holder_name` | string | Name on the account                       |
| `account_number`      | string | Account number (may be masked)            |
| `bank_name`           | string | Bank name                                 |
| `account_type`        | string | Type of account (Checking, Savings, etc.) |
| `routing_number`      | string | Bank routing number                       |
| `statement_date`      | string | Statement date (YYYY-MM-DD)               |
| `address`             | string | Address associated with account           |

## Error Responses

### 400 Bad Request - Invalid Image Format

```json theme={null}
{
  "error": "Invalid image format",
  "message": "Unsupported MIME type. Supported types: image/jpeg, image/png, application/pdf"
}
```

### 400 Bad Request - Missing Images

```json theme={null}
{
  "error": "Missing required parameter: images"
}
```

### 400 Bad Request - Invalid Base64

```json theme={null}
{
  "error": "Invalid base64 encoding",
  "message": "Failed to decode image data"
}
```

### 500 Internal Server Error - Processing Failed

```json theme={null}
{
  "error": "Error processing document",
  "message": "Failed to extract data from document"
}
```

## Status Codes

| Code | Description                                      |
| ---- | ------------------------------------------------ |
| 200  | Success - Document processed and data extracted  |
| 400  | Bad Request - Invalid parameters or image format |
| 401  | Unauthorized - Missing or invalid token          |
| 403  | Forbidden - Insufficient permissions             |
| 500  | Internal Server Error                            |

## Usage Examples

### Python Example

```python theme={null}
import requests
import base64

token = "YOUR_TOKEN"

# Read image file and encode as base64
with open("id_document.jpg", "rb") as f:
    image_data = base64.b64encode(f.read()).decode('utf-8')

response = requests.post(
    "https://stg.kyc.legaltalent.ai/kyc/documents/id",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    },
    json={
        "images": [
            {
                "data": image_data,
                "mime_type": "image/jpeg"
            }
        ]
    }
)

if response.status_code == 200:
    data = response.json()
    print(f"Verification ID: {data['verification_id']}")
    print(f"Extracted Name: {data['extracted_data']['full_name']}")
    print(f"Confidence: {data['confidence_scores']['overall']}")
else:
    print(f"Error: {response.json()}")
```

### JavaScript Example

```javascript theme={null}
const token = "YOUR_TOKEN";
const fs = require('fs');

async function extractDocumentData(filePath, documentType) {
  // Read file and encode as base64
  const fileBuffer = fs.readFileSync(filePath);
  const base64Data = fileBuffer.toString('base64');
  
  // Determine MIME type from file extension
  const mimeType = filePath.endsWith('.pdf') 
    ? 'application/pdf' 
    : filePath.endsWith('.png') 
    ? 'image/png' 
    : 'image/jpeg';
  
  const endpoint = `https://stg.kyc.legaltalent.ai/kyc/documents/${documentType}`;
  
  const response = await fetch(endpoint, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${token}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      images: [
        {
          data: base64Data,
          mime_type: mimeType
        }
      ]
    })
  });
  
  const data = await response.json();
  
  if (response.ok) {
    console.log(`Verification ID: ${data.verification_id}`);
    console.log(`Extracted Data:`, data.extracted_data);
    console.log(`Confidence: ${data.confidence_scores.overall}`);
    return data;
  } else {
    console.error("Error:", data.error);
    throw new Error(data.error);
  }
}
```

## Best Practices

* **Image Quality**: Use high-quality images (minimum 300 DPI) for best results
* **File Size**: Keep images under 10MB for optimal performance
* **Multiple Pages**: For multi-page documents (PDFs), include all pages in the images array
* **Confidence Scores**: Review confidence scores before using extracted data
* **Manual Verification**: Always verify extracted data manually for critical operations
* **Error Handling**: Implement proper error handling for processing failures

## Performance

* **Typical Response Time**: 2-5 seconds per document
* **Rate Limits**: Subject to API rate limiting (1,000 requests per 5 minutes)
* **File Size Limits**: Maximum 10MB per image
* **Concurrent Processing**: Process multiple documents in separate requests

## LLM Provider Options

### AWS Bedrock (Default)

* **Provider**: `"bedrock"` (default)
* **Model**: Uses default Bedrock model
* **Use Case**: Production deployments on AWS

### OpenAI

* **Provider**: `"openai"`
* **Model**: Specify model (e.g., `"gpt-4o"`)
* **Use Case**: High-precision extraction, specific model requirements

## Integration Tips

1. **Pre-processing**: Ensure images are properly oriented and well-lit
2. **Batch Processing**: Process multiple documents in separate requests
3. **Caching**: Consider caching verification IDs for reference
4. **Validation**: Validate extracted data against business rules before use
