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

# Import Data from Another Provider

> Create an asynchronous import job for historical User Verification sessions, Business Verification sessions, transaction monitoring records, or workflow custom status rules. Use this to migrate from providers such as Sumsub, MetaMap, Veriff, Onfido, Persona, Trulioo, Jumio, Incode, iDenfy, or any other provider after transforming the export into Didit's canonical CSV/NDJSON format. Imports are disabled by default and must be enabled per organization by Didit.

export const AgentPromptAccordion = ({prompt, title = "AI Agent Integration Prompt"}) => {
  const [copied, setCopied] = React.useState(false);
  const handleCopy = e => {
    e.stopPropagation();
    if (!prompt) return;
    navigator.clipboard.writeText(prompt.trim()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  };
  const agents = ["Claude Code", "Codex", "Cursor", "Devin", "Windsurf", "GitHub Copilot"];
  return <div className="didit-agent-card">
      {}
      <div className="didit-agent-titlebar">
        <div className="didit-agent-dots" aria-hidden="true">
          <span className="didit-agent-dot didit-agent-dot-red"></span>
          <span className="didit-agent-dot didit-agent-dot-yellow"></span>
          <span className="didit-agent-dot didit-agent-dot-green"></span>
        </div>
        <span className="didit-agent-filename">{title}</span>
        <button type="button" className={`didit-agent-copy ${copied ? "didit-agent-copy-copied" : ""}`} onClick={handleCopy} title="Copy prompt to clipboard" aria-label={copied ? "Copied!" : "Copy prompt to clipboard"}>
          {copied ? <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <path d="M3 8.5l3.5 3.5L13 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              <span>Copied</span>
            </> : <>
              <svg width="13" height="13" viewBox="0 0 16 16" fill="none">
                <rect x="5" y="5" width="9" height="9" rx="1.5" stroke="currentColor" strokeWidth="1.5" />
                <path d="M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              <span>Copy</span>
            </>}
        </button>
      </div>

      {}
      <pre className="didit-agent-body"><code>{prompt.trim()}</code></pre>

      {}
      <div className="didit-agent-footer">
        <span className="didit-agent-footer-label">Paste into</span>
        <div className="didit-agent-chips">
          {agents.map(name => <span key={name} className="didit-agent-chip">{name}</span>)}
        </div>
      </div>
    </div>;
};

Use this guide to choose the right import path when you move data from another provider into Didit. There are two different jobs customers often call "import":

* **Import historical verification work** — recreate completed KYC, KYB, transaction monitoring, or workflow-rule records so Didit shows the old provider history. Use `POST /v3/session/imports/`.
* **Import operating data** — create Users, Businesses, profile faces, blocklist entries, or allowlist entries so Didit can use them in future checks. Use the entity, face, and list APIs.

Verification imports create historical records with `session_type: "MIGRATED"` for KYC and KYB. They do not send end-user emails, do not redirect users into the hosted flow, and do not re-run the original verification. The imported records appear in session lists, entity profiles, transaction views, and `GET /v3/session/{session_id}/decision/` where applicable.

## Which import should you use?

| Goal                                               | Use this import path                                                                                                        | What it creates                                                                                                | Best for                                                                                                                           |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Recreate historical KYC sessions                   | `POST /v3/session/imports/` with `import_type=user_verification`                                                            | `Session`, ID Verification data, optional document/selfie images, document and liveness videos, tags, metadata | Moving completed applicants from Sumsub, MetaMap, Veriff, Onfido, Persona, Jumio, Incode, iDenfy, Trulioo, or another KYC provider |
| Recreate historical KYB sessions                   | `POST /v3/session/imports/` with `import_type=business_verification`                                                        | `BusinessSession`, registry company data, officers, beneficial owners, tags, metadata                          | Moving completed business checks from KYB vendors, company registry providers, or internal KYB tooling                             |
| Recreate historical transaction monitoring records | `POST /v3/session/imports/` with `import_type=transactions`                                                                 | `Transaction`, subject/counterparty parties, provider results, Travel Rule data, network snapshot, metadata    | Moving rule-engine, KYT, wallet-screening, or fiat transaction monitoring history                                                  |
| Import custom workflow status rules                | `POST /v3/session/imports/` with `import_type=status_rules`                                                                 | `VerificationSettings.feature_status_rules`                                                                    | Moving policy logic from another provider or spreadsheet into Didit's workflow engine                                              |
| Create Users without historical sessions           | `POST /v3/users/create/` or Console CSV import                                                                              | `VendorUser` profile rows                                                                                      | Loading your user roster before starting new Didit checks                                                                          |
| Attach trusted profile faces to users              | `POST /v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/` | Profile face evidence indexed for duplicate detection and face search                                          | Migrating profile face images from another KYC provider without recreating full sessions                                           |
| Blocklist or allowlist faces                       | `POST /v3/lists/{list_uuid}/entries/face-upload/` or `POST /v3/lists/{list_uuid}/entries/` with `reference_session_id`      | Face list entry and biometric embedding                                                                        | Migrating known fraud faces, trusted allowlist faces, or blocklisting a face from an existing Didit session                        |
| Create Businesses without historical KYB sessions  | `POST /v3/businesses/create/` or Console CSV import                                                                         | `VendorBusiness` profile rows                                                                                  | Loading a business customer roster before running KYB                                                                              |

<Note>
  If you only need a user or business profile for future checks, do not import a historical verification session. Use the User or Business entity APIs. If you need the old provider's decision, document fields, warnings, or evidence to appear as compliance history in Didit, use `POST /v3/session/imports/`.
</Note>

## What can migrate from each provider?

Didit accepts a canonical CSV or NDJSON file, so you can migrate from any provider once you export and transform the data. The import contract is always Didit's canonical schema.

| Provider family                        | Typical sources                                                                                                                      | Usually migratable                                                                                                                                    | Notes                                                                                                                              |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| KYC providers                          | Sumsub, MetaMap, Veriff, Onfido, Persona, Jumio, Incode, iDenfy, Trulioo, HyperVerge, AU10TIX, Mitek, Ondato                         | Applicant id, vendor user id, decision status, document fields, document images, selfie/liveness image, rejection labels, tags, raw provider metadata | Use `import_type=user_verification`. If the provider cannot export images, import the structured fields and keep image URLs empty. |
| KYB providers                          | Company registry providers, Sumsub KYB, Trulioo KYB, Creditsafe-style registry exports, internal KYB tools                           | Company name, registration number, country, registry status, officers, beneficial owners, risk level, raw registry payload                            | Use `import_type=business_verification`. Officers and UBOs are passed as JSON arrays.                                              |
| Transaction monitoring / KYT providers | Sumsub Transaction Monitoring, Chainalysis-style KYT exports, Crystal, Merkle Science, Sardine, Unit21, Alloy, internal rule engines | Transaction id, amount, currency, direction, subject/counterparty, rule hits, provider results, Travel Rule status, network graph snapshot            | Use `import_type=transactions`. Imported transactions are historical records; they are not re-screened by default.                 |
| Workflow and policy spreadsheets       | Compliance policy exports, provider rule tables, internal risk spreadsheets                                                          | Per-feature status rules such as "if issuing country is X, set ID Verification to In Review"                                                          | Use `import_type=status_rules`. Rules are validated against Didit's workflow field catalog before they are saved.                  |
| User/profile stores                    | CRM, customer DB, provider user export, data warehouse                                                                               | `vendor_data`, display name, metadata, tags, trusted face images                                                                                      | Use User APIs and profile face upload. This is not the same as a completed verification session.                                   |
| Blocklist / allowlist data             | Provider fraud lists, internal fraud ops sheets, chargeback lists, sanctions-adjacent internal lists                                 | Emails, phones, documents, wallets, IPs, device fingerprints, faces, countries, users, businesses                                                     | Use Lists APIs. For face images, use the dedicated face upload endpoint so Didit can extract the biometric embedding.              |

## Migration workflow

1. Decide whether you are importing history, profiles, faces, lists, transactions, or rules.
2. Export the data from the old provider yourself. Do not send old-provider API keys to Didit.
3. Transform the provider export into the matching Didit canonical CSV or NDJSON template.
4. For large migrations, prefer NDJSON and split into files you can retry independently.
5. Create the import job and poll progress.
6. Fetch row errors, fix only failed rows, and retry them. All import jobs are idempotent on their natural external id.

## Create an import job

Create an import job with a single multipart request:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/session/imports/ \
  -H "x-api-key: YOUR_API_KEY" \
  -F "import_type=user_verification" \
  -F "workflow_id=YOUR_KYC_WORKFLOW_ID" \
  -F "file=@didit-import.ndjson"
```

Use CSV for smaller spreadsheet-driven migrations and NDJSON for large migrations. For 100k+ rows, NDJSON is easier to stream, split, validate, and retry.

For transaction imports, omit `workflow_id`:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/session/imports/ \
  -H "x-api-key: YOUR_API_KEY" \
  -F "import_type=transactions" \
  -F "file=@didit-transactions.ndjson"
```

### Request fields

| Field             | Required                            | Description                                                                                                                                                                                    |
| ----------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `import_type`     | No, defaults to `user_verification` | One of `user_verification`, `business_verification`, `status_rules`, `transactions`.                                                                                                           |
| `workflow_id`     | Yes, except for `transactions`      | UUID of the workflow the imported records attach to. `user_verification` and `status_rules` need a User Verification workflow; `business_verification` needs a Business Verification workflow. |
| `file`            | Either `file` or `source_file_url`  | The canonical CSV or NDJSON file, uploaded inline.                                                                                                                                             |
| `source_file_url` | Either `file` or `source_file_url`  | HTTPS URL Didit downloads the file from. Private-network URLs are rejected.                                                                                                                    |
| `source_format`   | No                                  | `csv` or `ndjson`. Inferred from the file extension when omitted.                                                                                                                              |

### How records are tracked and deduplicated

There is no request field for the data source — every import uses Didit's canonical schema. Each imported record stores `metadata.imported_from = "generic"` for traceability.

`user_verification` and `business_verification` imports deduplicate rows on `external_id` within the application, so retrying the same file won't create duplicates. `transactions` imports deduplicate on `transaction_id` instead.

## Import document photos, videos, and selfie evidence

For `import_type=user_verification`, you can import the original document photos, document/liveness capture videos, and selfie image from the previous provider.

Use these canonical columns:

| Evidence                | Preferred column           | Small-import fallback   | Stored in Didit as              |
| ----------------------- | -------------------------- | ----------------------- | ------------------------------- |
| Document front image    | `document_front_url`       | `document_front_base64` | ID Verification OCR front image |
| Document back image     | `document_back_url`        | `document_back_base64`  | ID Verification OCR back image  |
| Selfie / liveness image | `selfie_url`               | `selfie_base64`         | Face/Liveness reference image   |
| Document front video    | `document_front_video_url` | URL only                | ID Verification OCR front video |
| Document back video     | `document_back_video_url`  | URL only                | ID Verification OCR back video  |
| Liveness video          | `liveness_video_url`       | URL only                | Face/Liveness capture video     |

For large migrations, use **HTTPS URLs**. Didit downloads each file, validates the URL is safe, stores a Didit-owned copy, and links it to the imported session. Images are compressed; videos are stored as-is. Inline base64 is accepted for images on small imports, but **videos must always be supplied as a URL** — base64 would inflate each video by \~33% and quickly exceed the per-file import limit.

Example NDJSON row with provider-hosted media URLs:

```json theme={null}
{
  "external_id": "applicant-123",
  "vendor_data": "user-42",
  "created_at": "2025-01-12T10:30:00Z",
  "status": "Approved",
  "email": "user@example.com",
  "phone": "+34687020083",
  "first_name": "Jane",
  "last_name": "Doe",
  "date_of_birth": "1990-05-15",
  "document_type": "P",
  "issuing_state": "USA",
  "document_number": "123456789",
  "expiration_date": "2030-01-15",
  "document_front_url": "https://provider-export.example.com/files/applicant-123-front.jpg",
  "document_back_url": "https://provider-export.example.com/files/applicant-123-back.jpg",
  "selfie_url": "https://provider-export.example.com/files/applicant-123-selfie.jpg",
  "document_front_video_url": "https://provider-export.example.com/files/applicant-123-front.webm",
  "document_back_video_url": "https://provider-export.example.com/files/applicant-123-back.webm",
  "liveness_video_url": "https://provider-export.example.com/files/applicant-123-liveness.mp4",
  "reject_reasons_json": "[]",
  "provider_metadata_json": "{\"source\":\"sumsub-export\"}"
}
```

Important media rules:

* URLs must use `https`.
* URLs must not resolve to private IPs, localhost, link-local ranges, or internal metadata hosts.
* Images accept either a URL column or its `*_base64` fallback; base64 takes precedence when both are set. Videos are URL only — there is no `*_video_base64` column.
* Videos must be `mp4`, `webm`, or `mov`, and each video may be at most **10 MB**. Larger or non-video files are rejected as row errors.
* Didit enforces connect/read timeouts, maximum file size, and no infinite retries.
* Media download failures are stored as row errors so the rest of the import can continue.
* If you do not have media from the provider, leave these columns empty. Didit still imports the structured decision and document fields.
* Imported images and videos are evidence for historical review. Didit does not re-run OCR, liveness, or document-fraud analysis on imported historical media by default.

<AgentPromptAccordion
  title="User Verification Import Prompt"
  prompt={`You are helping migrate historical User Verification (KYC) sessions into Didit.

Goal:
Transform the customer's Sumsub, MetaMap, or provider export into Didit's canonical verification import file, then call Didit's import API.

Didit API:
- Create import job: POST https://verification.didit.me/v3/session/imports/
- Poll job: GET https://verification.didit.me/v3/session/imports/{import_id}/
- Read row errors: GET https://verification.didit.me/v3/session/imports/{import_id}/errors/
- Download template: GET https://verification.didit.me/v3/session/imports/template/?import_type=user_verification
- Authenticate with x-api-key: <DIDIT_API_KEY>

Inputs you need:
- DIDIT_API_KEY
- DIDIT_WORKFLOW_ID for a User Verification workflow
- Provider export file or API output

Canonical columns:
external_id, vendor_data, created_at, status, email, phone, first_name, last_name, date_of_birth, gender, nationality, document_type, issuing_state, document_number, personal_number, expiration_date, document_front_url, document_back_url, selfie_url, document_front_base64, document_back_base64, selfie_base64, document_front_video_url, document_back_video_url, liveness_video_url, is_blocklisted, reject_reasons_json, tags, provider_metadata_json

Rules:
- phone is optional and accepts international format (for example +34687020083); it is stored on the imported session.
- external_id must be the provider's unique verification/applicant id.
- vendor_data must be the customer's stable user id. If absent, use the provider identity/user id.
- status must be Approved, Declined, In Review, or Expired.
- date_of_birth and expiration_date must use YYYY-MM-DD.
- created_at must be ISO 8601.
- nationality and issuing_state must be ISO-3166 alpha-3, for example USA, ESP, BRA.
- document_type must use Didit codes: P, ID, DL, RP, SSC, HIC, WP, TC, VISA, PSC, BC, OTHER.
- reject_reasons_json must be a JSON array. provider_metadata_json must be a JSON object.
- Use document_front_url, document_back_url, and selfie_url when the provider can export evidence images. Use HTTPS media URLs for large imports. Avoid inline base64 unless the import is small.
- Use document_front_video_url, document_back_video_url, and liveness_video_url to import capture videos. Videos must be mp4, webm, or mov and at most 10 MB each; otherwise the row is rejected.
- If only one document side exists, fill document_front_url and leave document_back_url empty.
- Never call the import API with provider credentials. The customer downloads provider data themselves.
- The import is idempotent by external_id inside one Didit application, so retries are safe.

Steps:
1. Inspect the provider export schema.
2. Map each provider row to the canonical fields.
3. Write NDJSON for large files; one JSON object per line.
4. Validate the first 10 rows locally before uploading.
5. Create an import job:
curl -X POST https://verification.didit.me/v3/session/imports/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-F "import_type=user_verification" \\
-F "workflow_id=$DIDIT_WORKFLOW_ID" \\
-F "file=@didit-import.ndjson"
6. Poll until status is COMPLETED or FAILED.
7. If failed_count is greater than 0, fetch /errors/ and produce a corrected file containing only failed rows.

Output:
- A canonical CSV or NDJSON file ready for Didit.
- The curl command used to create the import job.
- The import_id and polling command.
- A short summary of created, skipped, and failed rows.`}
/>

<AgentPromptAccordion
  title="Business Verification Import Prompt"
  prompt={`You are helping migrate historical Business Verification (KYB) sessions into Didit.

Goal:
Transform the customer's KYB provider export into Didit's canonical business verification import file, then call Didit's import API.

Didit API:
- Create import job: POST https://verification.didit.me/v3/session/imports/
- Poll job: GET https://verification.didit.me/v3/session/imports/{import_id}/
- Read row errors: GET https://verification.didit.me/v3/session/imports/{import_id}/errors/
- Download template: GET https://verification.didit.me/v3/session/imports/template/?import_type=business_verification
- Authenticate with x-api-key: <DIDIT_API_KEY>

Inputs you need:
- DIDIT_API_KEY
- DIDIT_WORKFLOW_ID for a Business Verification workflow
- Provider export file or API output

Canonical business columns:
external_id, vendor_data, created_at, status, company_name, registration_number, country_code, registry_status, verification_status, company_type, tax_number, risk_level, incorporation_date, registered_address, is_from_registry, officers_json, beneficial_owners_json, provider_metadata_json, tags

Rules:
- external_id must be the provider's unique business verification id.
- vendor_data must be the customer's stable business id.
- status must be Approved, Declined, In Review, or Expired.
- country_code must be ISO-3166 alpha-3.
- officers_json and beneficial_owners_json must be JSON arrays of objects.
- provider_metadata_json must be a JSON object.
- The import is idempotent by external_id inside one Didit application.

Create an import job:
curl -X POST https://verification.didit.me/v3/session/imports/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-F "import_type=business_verification" \\
-F "workflow_id=$DIDIT_WORKFLOW_ID" \\
-F "file=@didit-business-import.ndjson"

Output:
- A canonical CSV or NDJSON file ready for Didit.
- The curl command used to create the import job.
- The import_id and polling command.
- A short summary of created, skipped, and failed rows.`}
/>

<AgentPromptAccordion
  title="Custom Status Rules Import Prompt"
  prompt={`You are helping import custom status rules into a Didit workflow.

Goal:
Transform the customer's policy spreadsheet into Didit's feature_status_rules format, then call Didit's import API.

Didit API:
- Create import job: POST https://verification.didit.me/v3/session/imports/
- Poll job: GET https://verification.didit.me/v3/session/imports/{import_id}/
- Read row errors: GET https://verification.didit.me/v3/session/imports/{import_id}/errors/
- Download template: GET https://verification.didit.me/v3/session/imports/template/?import_type=status_rules
- Authenticate with x-api-key: <DIDIT_API_KEY>

Inputs you need:
- DIDIT_API_KEY
- DIDIT_WORKFLOW_ID for the workflow to update
- A policy spreadsheet or JSON policy definition

Canonical status-rule columns:
feature, rules_json, mode

Rules:
- feature must be a Didit feature key such as OCR, LIVENESS, FACE_MATCH, AML, KYB_REGISTRY, KYB_DOCUMENTS, or KYB_KEY_PEOPLE.
- rules_json must be a JSON array of rule objects.
- Each rule needs field, operator, status, and usually value.
- mode is replace or append. Default is replace.
- Do not reference status fields such as kyc.status; status rules compute status and must use other report fields.

Example rules_json:
[{"field":"kyc.issuing_state","operator":"in","value":["VEN","IRN"],"status":"In Review"}]

Create an import job:
curl -X POST https://verification.didit.me/v3/session/imports/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-F "import_type=status_rules" \\
-F "workflow_id=$DIDIT_WORKFLOW_ID" \\
-F "file=@didit-status-rules.csv"

Output:
- A canonical CSV or NDJSON file ready for Didit.
- The curl command used to create the import job.
- The import_id and polling command.
- A summary of updated and failed rule rows.`}
/>

<AgentPromptAccordion
  title="Transaction Import Prompt"
  prompt={`You are helping migrate historical transaction monitoring records into Didit.

Goal:
Transform the customer's legacy transaction monitoring export into Didit's canonical transaction import file, then call Didit's import API.

Didit API:
- Create import job: POST https://verification.didit.me/v3/session/imports/
- Poll job: GET https://verification.didit.me/v3/session/imports/{import_id}/
- Read row errors: GET https://verification.didit.me/v3/session/imports/{import_id}/errors/
- Download template: GET https://verification.didit.me/v3/session/imports/template/?import_type=transactions
- Authenticate with x-api-key: <DIDIT_API_KEY>

Inputs you need:
- DIDIT_API_KEY
- A transaction export file or API output

Canonical transaction columns:
transaction_id, transaction_at, transaction_category, direction, amount, currency, currency_kind, amount_in_default_currency, default_currency, payment_details, payment_reference_id, action_type, status, score, severity, subject_json, counterparty_json, custom_properties_json, provider_results_json, travel_rule_json, network_snapshot_json, metadata_json

Rules:
- transaction_id is required and is idempotent per Didit application.
- transaction_category must be one of Didit's transaction categories, for example finance, kyc, travelRule, userPlatformEvent, gamblingBet, gamblingLimitChange, gamblingBonusChange, or auditTrailEvent.
- direction must be INBOUND or OUTBOUND.
- status must be APPROVED, IN_REVIEW, DECLINED, or AWAITING_USER.
- subject_json must include vendor_data and full_name.
- counterparty_json is optional but should be included when the legacy provider has it.
- provider_results_json must be a JSON array.
- travel_rule_json, network_snapshot_json, custom_properties_json, and metadata_json must be JSON objects when present.

Create an import job:
curl -X POST https://verification.didit.me/v3/session/imports/ \\
-H "x-api-key: $DIDIT_API_KEY" \\
-F "import_type=transactions" \\
-F "file=@didit-transactions.ndjson"

Output:
- A canonical CSV or NDJSON file ready for Didit.
- The curl command used to create the import job.
- The import_id and polling command.
- A summary of created, skipped, and failed transaction rows.`}
/>

## Poll progress

```bash theme={null}
curl https://verification.didit.me/v3/session/imports/IMPORT_ID/ \
  -H "x-api-key: YOUR_API_KEY"
```

The response includes `status`, `import_type`, `total_rows`, `processed_rows`, `created_count`, `updated_count`, `skipped_count`, `failed_count`, and `checkpoint_row`.

## Download row errors

```bash theme={null}
curl https://verification.didit.me/v3/session/imports/IMPORT_ID/errors/ \
  -H "x-api-key: YOUR_API_KEY"
```

Each error includes `row_number`, `external_id`, `error`, and `raw_row`, so you can fix only the failed rows and retry.

## Abuse protection

Historical import jobs through `POST /v3/session/imports/` are disabled by default. Didit enables this capability per organization after review because these jobs can process millions of rows and download media. The normal operating-data imports in this guide — creating Users, creating Businesses, uploading profile faces, uploading face blocklists, or adding list entries — do not require special migration enablement beyond the normal API key permissions, product availability, and rate limits for those endpoints.

Historical import jobs also run on isolated workers with file size limits, row budgets, HTTPS-only media URLs, private-network URL blocking, per-application active-job limits, and per-row error capture.

## Canonical statuses

| Provider outcome                           | Didit status |
| ------------------------------------------ | ------------ |
| Approved / Green / Verified                | `Approved`   |
| Declined / Red / Rejected                  | `Declined`   |
| Manual review / Pending / Review needed    | `In Review`  |
| Incomplete / Init / Unknown historical row | `Expired`    |

## Idempotency

Didit uses `external_id` as the import idempotency key for User Verification and Business Verification imports, scoped per application. Transaction imports use `transaction_id` per application. Retrying the same file skips rows that were already imported and creates rows that were not processed yet.

## Import users, profile faces, and blocklists

Use these paths when you are not recreating a completed verification session:

### Import user profiles

Create users with [`POST /v3/users/create/`](/management-api/users/create) or the Business Console CSV import in [Import and Export Users](/entities/users/import-export). This creates or updates the `VendorUser` profile only. It does not create a verification session, KYC decision, document report, warning, or webhook history.

Use this when you want Didit to know the customer exists before future checks, or when you need to backfill CRM-like fields such as `display_name`, tags, or metadata.

### Upload trusted profile faces

After a User exists, upload a trusted profile face with [`POST /v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/`](/management-api/users/upload-face). This attaches biometric evidence to the User profile and indexes it for duplicate detection and face search.

This does **not** blocklist the face. It is useful when you have a trusted profile image from a previous KYC provider and want future Didit checks to compare against it.

### Import face blocklists and allowlists

To block or allow a face directly, use [`POST /v3/lists/{list_uuid}/entries/face-upload/`](/management-api/lists/upload-face) with a face-type list. Didit extracts the biometric embedding and stores a list entry.

Use this for known fraudster images, trusted allowlist faces, or provider fraud-list migrations. If the face comes from an existing Didit session, prefer [`POST /v3/lists/{list_uuid}/entries/`](/management-api/lists/create-entry) with `reference_session_id`; Didit extracts the right face from the session and links the entry back to the source.

### Import user, business, document, wallet, email, phone, IP, or device lists

Use [`POST /v3/lists/{list_uuid}/entries/`](/management-api/lists/create-entry) for non-face list values. This is the right path for provider blocklists, allowlists, chargeback lists, wallet addresses, known risky IPs, device fingerprints, document numbers, emails, phones, users, or businesses.

## Next steps

<CardGroup cols={3}>
  <Card title="Import users" icon="users" href="/entities/users/import-export">
    Load User profiles and attach trusted profile faces.
  </Card>

  <Card title="Import businesses" icon="building" href="/entities/businesses/import-export">
    Load Business profiles before running KYB.
  </Card>

  <Card title="Upload profile face" icon="face-viewfinder" href="/management-api/users/upload-face">
    Attach trusted face images to imported Users.
  </Card>

  <Card title="Upload face to list" icon="ban" href="/management-api/lists/upload-face">
    Add faces to blocklists or allowlists.
  </Card>

  <Card title="Create list entry" icon="list" href="/management-api/lists/create-entry">
    Import phones, emails, wallets, documents, IPs, devices, users, or businesses into lists.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/integration/rate-limiting">
    Design safe migration loops and retries.
  </Card>
</CardGroup>


## OpenAPI

````yaml POST /v3/session/imports/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/session/imports/:
    post:
      tags:
        - Sessions
      summary: Create a verification import job
      description: >-
        Create an asynchronous import job for historical User Verification
        sessions, Business Verification sessions, transaction monitoring
        records, or workflow custom status rules. Use this to migrate from
        providers such as Sumsub, MetaMap, Veriff, Onfido, Persona, Trulioo,
        Jumio, Incode, iDenfy, or any other provider after transforming the
        export into Didit's canonical CSV/NDJSON format. Imports are disabled by
        default and must be enabled per organization by Didit.
      operationId: post_v3_session_imports_create
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                import_type:
                  type: string
                  enum:
                    - user_verification
                    - business_verification
                    - status_rules
                    - transactions
                  default: user_verification
                  description: >-
                    What to import: historical User Verification sessions,
                    historical Business Verification sessions, workflow custom
                    status rules, or historical transaction monitoring records.
                workflow_id:
                  type: string
                  format: uuid
                  description: >-
                    Workflow UUID that imported sessions or status rules should
                    be attached to. Required for user_verification,
                    business_verification, and status_rules. Omit for
                    transactions.
                source_format:
                  type: string
                  enum:
                    - csv
                    - ndjson
                  description: >-
                    Optional. Inferred from the uploaded file extension when
                    omitted.
                file:
                  type: string
                  format: binary
                  description: >-
                    Canonical CSV or NDJSON file. Use NDJSON for large imports.
                    Maximum upload size 25 MB (use `source_file_url` for bigger
                    files). Mutually exclusive with `source_file_url`.
                source_file_url:
                  type: string
                  format: uri
                  description: >-
                    Alternative to file upload. Must be an HTTPS URL resolving
                    to a public address (private/loopback networks are
                    rejected). Mutually exclusive with `file`.
          application/json:
            schema:
              type: object
              required:
                - source_file_url
              properties:
                import_type:
                  type: string
                  enum:
                    - user_verification
                    - business_verification
                    - status_rules
                    - transactions
                  default: user_verification
                  description: >-
                    What to import: historical User Verification sessions,
                    historical Business Verification sessions, workflow custom
                    status rules, or historical transaction monitoring records.
                workflow_id:
                  type: string
                  format: uuid
                  description: >-
                    Workflow UUID that imported sessions or status rules should
                    be attached to. Required for user_verification,
                    business_verification, and status_rules. Omit for
                    transactions.
                source_format:
                  type: string
                  enum:
                    - csv
                    - ndjson
                  description: >-
                    Optional. Inferred from the URL's file extension when
                    omitted.
                source_file_url:
                  type: string
                  format: uri
                  description: >-
                    Alternative to file upload. Must be an HTTPS URL resolving
                    to a public address (private/loopback networks are
                    rejected). Mutually exclusive with `file`.
            examples:
              URL-based import:
                value:
                  import_type: user_verification
                  workflow_id: 9f9b1234-aaaa-bbbb-cccc-1234567890ab
                  source_file_url: https://files.example.com/exports/sessions.ndjson
      responses:
        '201':
          description: >-
            Import job accepted. Poll the returned `uuid` until `status` is
            `COMPLETED` or `FAILED`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionImportJob'
              examples:
                Job accepted:
                  value:
                    uuid: 3f9c1a2b-4d5e-4f60-8a7b-9c0d1e2f3a4b
                    status: PENDING
                    import_type: user_verification
                    source_format: ndjson
                    source_filename: sessions.ndjson
                    total_rows: 0
                    processed_rows: 0
                    checkpoint_row: 0
                    created_count: 0
                    updated_count: 0
                    skipped_count: 0
                    failed_count: 0
                    total_media_bytes: 0
                    last_error: null
                    created_at: '2026-05-17T08:42:11Z'
                    updated_at: '2026-05-17T08:42:11Z'
                    started_at: null
                    completed_at: null
        '400':
          description: >-
            Invalid workflow, file type, file size, source URL, or selector
            combination.
          content:
            application/json:
              examples:
                Invalid workflow:
                  value:
                    workflow_id:
                      - Invalid workflow_id.
                Workflow required:
                  value:
                    workflow_id:
                      - This field is required for this import type.
                Wrong file type:
                  value:
                    file:
                      - Only CSV and NDJSON files are supported.
                File too large:
                  value:
                    file:
                      - Import file exceeds the maximum allowed size.
                No source:
                  value:
                    file:
                      - Upload a file or provide source_file_url.
                Both sources:
                  value:
                    file:
                      - Use either file or source_file_url, not both.
        '403':
          description: >-
            Imports not enabled, sandbox application, or missing/invalid API key
            (this endpoint returns `403`, never `401`, for authentication
            failures). Verification imports are disabled by default and must be
            enabled per organization by Didit.
          content:
            application/json:
              examples:
                Imports not enabled:
                  value:
                    detail: >-
                      Verification imports are not enabled for this
                      organization.
                Sandbox:
                  value:
                    detail: >-
                      Verification imports are not enabled for sandbox
                      applications.
                Bad API key:
                  value:
                    detail: You do not have permission to perform this action.
        '429':
          description: >-
            The application already has an active import job
            (PENDING/PROCESSING/PAUSED). Wait for it to finish before starting
            another.
          content:
            application/json:
              examples:
                Active job:
                  value:
                    detail: >-
                      This application already has an active import job. Wait
                      for it to finish before starting another.
      security:
        - ApiKeyAuth: []
components:
  schemas:
    SessionImportJob:
      type: object
      required:
        - uuid
        - status
        - import_type
        - source_format
        - source_filename
        - total_rows
        - processed_rows
        - created_count
        - updated_count
        - skipped_count
        - failed_count
      properties:
        uuid:
          type: string
          format: uuid
          description: Import job id. Use this value to poll progress and fetch row errors.
        status:
          type: string
          enum:
            - PENDING
            - PROCESSING
            - COMPLETED
            - FAILED
            - PAUSED
            - CANCELLED
        import_type:
          type: string
          enum:
            - user_verification
            - business_verification
            - status_rules
            - transactions
        source_format:
          type: string
          enum:
            - csv
            - ndjson
        source_filename:
          type: string
        total_rows:
          type: integer
          format: int64
        processed_rows:
          type: integer
          format: int64
        checkpoint_row:
          type: integer
          format: int64
        created_count:
          type: integer
          format: int64
        updated_count:
          type: integer
          format: int64
        skipped_count:
          type: integer
          format: int64
        failed_count:
          type: integer
          format: int64
        total_media_bytes:
          type: integer
          format: int64
        last_error:
          type: string
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        started_at:
          type: string
          format: date-time
          nullable: true
        completed_at:
          type: string
          format: date-time
          nullable: true
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key

````