Skip to main content
POST
Create a verification import job
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?

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

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.

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

Request fields

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

Poll progress

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

Download row errors

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

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/ or the Business Console CSV import in Import and Export Users. 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/. 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/ 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/ 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/ 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

Import users

Load User profiles and attach trusted profile faces.

Import businesses

Load Business profiles before running KYB.

Upload profile face

Attach trusted face images to imported Users.

Upload face to list

Add faces to blocklists or allowlists.

Create list entry

Import phones, emails, wallets, documents, IPs, devices, users, or businesses into lists.

Rate limits

Design safe migration loops and retries.

Authorizations

x-api-key
string
header
required

Body

import_type
enum<string>
default:user_verification

What to import: historical User Verification sessions, historical Business Verification sessions, workflow custom status rules, or historical transaction monitoring records.

Available options:
user_verification,
business_verification,
status_rules,
transactions
workflow_id
string<uuid>

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
enum<string>

Optional. Inferred from the uploaded file extension when omitted.

Available options:
csv,
ndjson
file
file

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
string<uri>

Alternative to file upload. Must be an HTTPS URL resolving to a public address (private/loopback networks are rejected). Mutually exclusive with file.

Response

Import job accepted. Poll the returned uuid until status is COMPLETED or FAILED.

uuid
string<uuid>
required

Import job id. Use this value to poll progress and fetch row errors.

status
enum<string>
required
Available options:
PENDING,
PROCESSING,
COMPLETED,
FAILED,
PAUSED,
CANCELLED
import_type
enum<string>
required
Available options:
user_verification,
business_verification,
status_rules,
transactions
source_format
enum<string>
required
Available options:
csv,
ndjson
source_filename
string
required
total_rows
integer<int64>
required
processed_rows
integer<int64>
required
created_count
integer<int64>
required
updated_count
integer<int64>
required
skipped_count
integer<int64>
required
failed_count
integer<int64>
required
checkpoint_row
integer<int64>
total_media_bytes
integer<int64>
last_error
string | null
created_at
string<date-time>
updated_at
string<date-time>
started_at
string<date-time> | null
completed_at
string<date-time> | null