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

# Running a Document Verification

> Verify a government ID document through the API — no SDK or session required.

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

1. Create a `document/idv` with file declarations and get presigned upload URLs
2. 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.

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

```json theme={null}
{
  "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
      }
    ]
  }
}
```

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

  ```json theme={null}
  {
    "data": {
      "type": "document/idv",
      "attributes": {
        "files": [
          { "filename": "id_card_front.jpeg" },
          { "filename": "id_card_back.jpeg" }
        ]
      }
    }
  }
  ```
</Tip>

## Step 2: Upload the Document Images

Upload each file to its corresponding presigned URL using a PUT request:

```bash theme={null}
curl -X PUT "{presigned_upload_url}" \
  -H "Content-Type: image/jpeg" \
  --data-binary @id_card.jpeg
```

<Info>
  The presigned URL expires after the time specified in `expires_in` (typically 1 hour). Upload your files before it expires.
</Info>

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:

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

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

```bash theme={null}
curl -X GET "https://api.beltic.com/v1/identity/verifications?filter[document_id]=doc_01HQ..." \
  -H "X-Api-Key: YOUR_API_KEY"
```

### Verification Response

```json theme={null}
{
  "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                       |
| ---------------- | ------------------------------------------- | -------------------------------- |
| `passed`         | The document passed all required checks     | Accept the verification          |
| `failed`         | One or more required checks failed          | Reject or investigate further    |
| `requires_retry` | Image 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

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

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

<AccordionGroup>
  <Accordion title="Image Quality">
    * 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
  </Accordion>

  <Accordion title="Two-Sided Documents">
    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
  </Accordion>

  <Accordion title="Supported Document Types">
    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
  </Accordion>
</AccordionGroup>

## Next Steps

* **Need sessions?** Learn how to [run verifications within a session](/guides/identity/sessions) for full onboarding flows
* **API Reference**: See the complete [Document IDV API reference](/api-reference/endpoint/identity-document-idvs-create)
