Bulk Client Import
Bulk Client Import lets you submit many customers for KYC/KYB verification in a single batch instead of creating and onboarding each one through separate API calls. You describe all customers in one manifest.json file, upload it together with their documents to a dedicated storage prefix, and start processing. The platform validates the data, creates the customers, submits them for compliance review and reports the outcome for every row.
A batch can contain individuals, companies (with their associated parties: UBOs, directors and authorized signatories), or both.
All Bulk Client Import methods live under /v2/compliance/batch and belong to the BatchService group of the Partner API.
When to use it
Migrating an existing customer base to Delos.
Onboarding customers in bulk from your CRM or back office.
Any case where calling Add Customer + application methods one by one would be slow or hard to track.
For onboarding a single customer, keep using Add Customer and Get Compliance Link.
Key concepts
Batch
A container for one import. It has a lifecycle status, row counters and its own storage prefix.
Schema snapshot
The verification requirements (fields, documents, questionnaire, associated-party roles) frozen when the batch is created. The batch is always validated against this snapshot, even if requirements change later.
Manifest
manifest.json in the root of the batch prefix. One item (row) per customer.
Row
One customer in the manifest, identified by your row_key. Each row has its own status and result.
Prefix
A private folder in Delos storage (S3-compatible) where you upload the manifest and documents using temporary credentials.
Batch lifecycle
OPEN
Created and waiting for files and a manifest.
Yes
CLOSED
Committed. The manifest is accepted and rows are being processed.
No
CHANGE_REQUESTED
Reopened by you for corrections after a commit.
Yes
CANCELLED
Closed permanently. Final state.
No
Transitions
Commit
OPEN, CHANGE_REQUESTED
CLOSED
409
Request changes
CLOSED
CHANGE_REQUESTED
No-op from CHANGE_REQUESTED, 409 from OPEN
Cancel
OPEN, CHANGE_REQUESTED
CANCELLED
No-op from CANCELLED, 409 from CLOSED
You can have at most 3 batches that are not closed at the same time. Cancel batches you no longer need to free a slot.
Integration flow
Base URL (Sandbox): https://partner.sandbox.delos.financial
All requests require the Authorization: Bearer <JWT> header. The partner is identified from the token; you never pass a partner ID.
Step 1. Create a batch
Select which customer types this batch will contain.
The response (201) is a Batch object. Save batch_id and schema_version. At this moment the platform freezes the schema snapshot for the selected types.
Step 2. Get the schema and the example manifest
The schema tells you exactly what to provide for each customer:
fields
Profile fields: required flag, value type, format
fields
documents
Allowed document types and document groups
documents
questionnaire
Questionnaire sections and questions: id, type, options, required flag
questionnaire
associated_parties
Companies only: required roles (UBO, director, etc.)
associated_parties
Use individual_schema for individual rows and company_schema for company rows. Each role in company_schema.associated_parties references a level; the fields and documents for that party are in associated_party_levels under that reference.
Fastest start: download the example manifest. It is generated from your batch's frozen schema and contains one row per selected type, every field with a "<required>" / "<optional>" placeholder, sample documents, questionnaire answers in the correct shape, and one party for each required company role. Replace the placeholders, remove optional parts you do not need, and save it as manifest.json. The same file is also placed in your prefix as example_manifest.json; the platform never reads it as data.
Step 3. Get storage credentials and upload documents
The response contains bucket, prefix, region and temporary credentials (access_key_id, secret_access_key, session_token, expiration). Credentials only work inside your batch prefix and are valid for about 12 hours. Request new ones with the same call when they expire. Credentials are issued only while the batch is OPEN or CHANGE_REQUESTED.
Upload all customer documents into the prefix. The folder structure is up to you; file paths in the manifest must match where you put the files.
Tip: add ?format=credential_process to receive credentials in the AWS credential_process format. The AWS CLI/SDK will then refresh them automatically:
File requirements
Formats: PDF, JPEG, PNG. The file content is checked, not the extension.
Maximum size: 50 MB per file.
Corrupted, password-protected or truncated files are rejected.
Step 4. Compose and upload manifest.json
Upload one manifest.json to the root of the prefix.
Step 5. Commit the batch
Make sure every file and the manifest are fully uploaded first. A successful commit returns 202: the batch becomes CLOSED and processing starts. Row validation runs asynchronously after the commit.
Do not overwrite manifest.json after a commit. The platform verifies the content of the accepted manifest and stops processing if it has been replaced.
Step 6. Track results
GET /v2/compliance/batch/{batch_id}
See row counters and the processed / done flags.
GET /v2/compliance/batch/{batch_id}/items
List rows, optionally filtered by status.
GET /v2/compliance/batch/{batch_id}/items/{row_key}
Get one row with full review details and rejection reasons.
GET /v2/compliance/batch/{batch_id}/status
Get a summary of problems with readable explanations, plus the list of created customers.
processed: truemeans every row has reachedsubmitted,invalidorfailed: onboarding is complete on your side.done: truemeans every row has a final result.
A report.json file with the outcome of every row also appears in your prefix. You can download it with credentials obtained before the commit, as long as they have not expired.
Manifest format
The manifest is a JSON object with an items array, one item per customer. You can optionally include schema_version; if it is omitted or empty, the batch's frozen snapshot is used. A schema_version from another batch is rejected.
Row fields
row_key
string
Yes
Your unique identifier of the row. Must be unique within the manifest. You use it to find the row's result.
external_customer_id
string
No
Your stable customer identifier. Prevents the same customer from being created twice, in this or any other batch. Cannot be changed after commit.
type
string
Yes
individual or company. Must be one of the types selected when the batch was created.
fields
object
Yes
Profile field values, keyed by field id from the schema.
documents
array
Yes
Documents: type, optional sub_type, file (path relative to the prefix).
questionnaire
object
If the schema has one
Answers: sections → section id → items → question id → answer.
associated_parties
array
Companies only
Company participants: party_key, roles in types, their own fields and documents.
Individual row example
Field ids, document types, questionnaire section and question ids above are examples. Always take them from your batch's schema or example manifest.
Validation rules
Fields. Every field with
required: truemust have a non-empty value of the correct type. If the schema defines aformat, the value must match it:date:
YYYY-MM-DDcountry: ISO 3166-1 alpha-2 code (e.g.
CY)email: a valid address with
@and a domainphone: E.164 (
+and up to 15 digits, no spaces or brackets)
Markup. Values containing
<or>are rejected in profile fields, free-text questionnaire answers andexternal_customer_id.Documents. The type must be allowed by the schema, and
filemust point to an uploaded file.Two-sided documents (ID card, residence permit, driver's licence) are sent as two entries of the same typewith
sub_typeFRONT_SIDEandBACK_SIDE. If you have both sides, send both. A back side without a front side is not accepted.A passport has no sides; send one entry without
sub_type.For companies, the document type is always
COMPANY_DOC; the specific document kind goes insub_type. Every required company document group must be covered by at least one file.
Questionnaire. The answer shape depends on the question type:
regular question:
valuemultiple-choice question:
values(each must be one of the question'soptions)file question:
files, a list of paths. Never put a file path invalue.
All required visible questions must be answered.
Associated parties (companies). Each party has its own
party_key, roles intypes(UBO,DIRECTOR,AUTHORIZED_SIGNATORY),fieldsanddocuments. Roles withcan_skip: falsein the schema are mandatory. For a UBO, pass the ownership share inshare_size.
How errors are handled
An error in a row marks only that row as
invalid; all other rows are processed.If the manifest as a whole cannot be accepted, the commit is rejected with
422and the batch stays editable. This happens whenmanifest.jsonis missing or too large, is not valid JSON, has trailing content, has no items, has more than 10,000 rows, or has a foreignschema_version.
Row statuses
invalid
The row failed manifest validation. The reason is in error.
valid
Passed validation, waiting to be processed.
creating
The customer is being created and the documents submitted.
submitted
Submitted for compliance review.
finished
Customer approved. Final.
rejected
Customer rejected. Final.
change_requested
Reviewers ask to correct data or documents.
failed
Could not be processed: broken file, duplicate customer or another permanent error. The reason is in error. Final.
Batch counters are always numbers, including zeros. Uploading files alone does not change them; before the first commit all counters are 0.
Where to find rejection details
GET .../statusreturnsproblems: rows ininvalid,failed,change_requestedorrejected, each with a readablesummary.GET .../items/{row_key}returns the fullreviewobject, including rejection reasons per document (document_reject_reasons), per associated party (party_reject_reasons) and per verification step (step_reject_reasons).
Corrections
A typical situation: some rows ended up invalid or change_requested.
Reopen the batch:
POST /v2/compliance/batch/{batch_id}/change. Status becomesCHANGE_REQUESTED.Get new credentials and upload the corrected files. Put a replacement document under a new path; do not overwrite the old file.
Upload the full manifest again. The manifest is always the source of truth: a row you remove that has not yet been submitted for review is withdrawn.
Commit again.
Rules for existing rows
Rows in a final state (
finished,rejected,failed) are never changed by a later commit.To retry a customer whose row is
failed, add a new row with a newrow_key.The
typeandexternal_customer_idof an existingrow_keycannot be changed.
Letting the customer fix it themselves
For a row in change_requested, you can request a fresh verification link and send it to the end customer:
The response contains url and ttl_seconds. For rows in any other status the call returns 409.
Cancelling a batch
POST /v2/compliance/batch/{batch_id}/cancel closes the batch permanently and frees a slot in the open-batch limit. It works for OPEN and CHANGE_REQUESTED batches.
Rows that were not yet submitted for review become
failed.Rows already submitted cannot be withdrawn and will still receive a result.
Errors
Errors are returned in the following format:
code is a gRPC status code; use the HTTP status of the response for your error handling.
400
Invalid request (e.g. empty or repeated types, unsupported format value).
403
Your partner account is not enabled for Bulk Client Import, or the token lacks the required scope.
404
The batch does not exist or belongs to another partner.
409
The action is not allowed in the batch's current status, the open-batch limit is reached, or a WebSDK link is requested for a row not in change_requested.
422
The manifest was rejected at commit. The batch stays editable.
503
The verification schema source is temporarily unavailable when creating a batch. Retry later.
Best practices
Start from the example manifest instead of building rows by hand.
Always send
external_customer_idso a customer is never created twice, even across batches.Upload everything before committing, and run uploads and commits sequentially, not in parallel.
Retry a commit only after checking the batch status. A repeated commit on a
CLOSEDbatch returns200but does not accept a new manifest.Use
processed, notdone, as your onboarding milestone.donealso waits for compliance decisions, which can take longer.Poll with reasonable intervals. Rows move asynchronously; there is no need to poll more often than once every few minutes.
Endpoint reference
List Batches
GET /v2/compliance/batch
List your batches.
Create Batch
POST /v2/compliance/batch
Create a batch and freeze its schema.
Get Batch
GET /v2/compliance/batch/{batch_id}
Batch status, counters and flags.
Get Batch Schema
GET /v2/compliance/batch/{batch_id}/schema
Frozen schema snapshot.
Get Example Manifest
GET /v2/compliance/batch/{batch_id}/example-manifest
Manifest template with placeholders.
Get Upload Credentials
GET /v2/compliance/batch/{batch_id}/credentials
Temporary storage credentials.
Commit Batch
POST /v2/compliance/batch/{batch_id}/commit
Start processing.
Request Batch Changes
POST /v2/compliance/batch/{batch_id}/change
Reopen a committed batch for corrections.
Cancel Batch
POST /v2/compliance/batch/{batch_id}/cancel
Close a batch permanently.
List Batch Items
GET /v2/compliance/batch/{batch_id}/items
List rows with a status filter.
Get Batch Item
GET /v2/compliance/batch/{batch_id}/items/{row_key}
One row with review details.
Get Item WebSDK Link
GET /v2/compliance/batch/{batch_id}/items/{row_key}/web_sdk_link
Verification link for a row in change_requested.
Get Batch Status
GET /v2/compliance/batch/{batch_id}/status
Problems summary and created customers.
Last updated

