curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"image": "/9j/4AAQSkZJRgABAQEA...", "comment": "Imported from previous KYC provider"}'import requests
resp = requests.post(
'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/',
headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},
json={
'image': '/9j/4AAQSkZJRgABAQEA...',
'comment': 'Imported from previous KYC provider',
},
)
resp.raise_for_status()
face = resp.json()
print(face['uuid'], face['image_url'])const resp = await fetch('https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/', {
method: 'POST',
headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
image: '/9j/4AAQSkZJRgABAQEA...',
comment: 'Imported from previous KYC provider',
}),
});
const face = await resp.json();
console.log(face.uuid, face.image_url);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '/9j/4AAQSkZJRgABAQEA...',
'comment' => 'Imported from previous KYC provider'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/"
payload := strings.NewReader("{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}"
response = http.request(request)
puts response.read_body{
"uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"image_url": "https://signed-url.example/face.jpg",
"comment": "Imported from previous KYC provider",
"uploaded_by": "api",
"created_at": "2026-05-18T12:00:00Z"
}Upload User Face
Attach a trusted imported face image to an existing User profile. Use this after creating or retrieving a User by vendor_data and reading its didit_internal_id. The uploaded face is stored on the User profile and indexed for duplicate detection and face search. It is not added to a face blocklist.
curl -X POST 'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"image": "/9j/4AAQSkZJRgABAQEA...", "comment": "Imported from previous KYC provider"}'import requests
resp = requests.post(
'https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/',
headers={'x-api-key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},
json={
'image': '/9j/4AAQSkZJRgABAQEA...',
'comment': 'Imported from previous KYC provider',
},
)
resp.raise_for_status()
face = resp.json()
print(face['uuid'], face['image_url'])const resp = await fetch('https://verification.didit.me/v3/organization/11111111-2222-3333-4444-555555555555/application/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/vendor-users/by-id/f4e5e1f2-94a9-4f86-8c16-2b7d9b4db418/faces/upload/', {
method: 'POST',
headers: { 'x-api-key': process.env.DIDIT_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({
image: '/9j/4AAQSkZJRgABAQEA...',
comment: 'Imported from previous KYC provider',
}),
});
const face = await resp.json();
console.log(face.uuid, face.image_url);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'image' => '/9j/4AAQSkZJRgABAQEA...',
'comment' => 'Imported from previous KYC provider'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/"
payload := strings.NewReader("{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image\": \"/9j/4AAQSkZJRgABAQEA...\",\n \"comment\": \"Imported from previous KYC provider\"\n}"
response = http.request(request)
puts response.read_body{
"uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"image_url": "https://signed-url.example/face.jpg",
"comment": "Imported from previous KYC provider",
"uploaded_by": "api",
"created_at": "2026-05-18T12:00:00Z"
}Overview
Use this endpoint when you import Users from another provider and already have a trusted face image for each person. The User remains keyed by yourvendor_data, but this profile attachment endpoint uses didit_internal_id so the target User is unambiguous.
Endpoint
POST /v3/organization/{organization_id}/application/{application_id}/vendor-users/by-id/{didit_internal_id}/faces/upload/
Migration flow
Create or find the User
POST /v3/users/create/ for a new profile, or GET /v3/users/{vendor_data}/ for an existing one.Store didit_internal_id
didit_internal_id. Keep using vendor_data in your database; use didit_internal_id only for profile attachment endpoints.Upload the face
image field. The backend validates image decoding, image size, and face detection before saving it.Example
# 1. Create the User keyed by your external id
curl -X POST https://verification.didit.me/v3/users/create/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"vendor_data": "user-42",
"display_name": "Jane Doe",
"metadata": { "previous_provider": "legacy-kyc-vendor" }
}'
# 2. Upload an imported face to the returned didit_internal_id
curl -X POST https://verification.didit.me/v3/organization/$ORGANIZATION_ID/application/$APPLICATION_ID/vendor-users/by-id/$DIDIT_INTERNAL_ID/faces/upload/ \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "<base64-encoded-jpg-or-png>",
"comment": "Imported from previous KYC provider"
}'
Request body
| Field | Type | Required | Description |
|---|---|---|---|
image | string | Yes | Raw base64-encoded JPG or PNG. Do not include data:image/...;base64,. Max decoded size: 2 MB. |
comment | string | No | Operator-visible note shown on the User profile. |
Response
{
"uuid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"image_url": "https://signed-url.example/face.jpg",
"comment": "Imported from previous KYC provider",
"uploaded_by": "api",
"created_at": "2026-05-18T12:00:00Z"
}
Validation and limits
- Max 5 manually uploaded faces per User.
- Max decoded image size is 2 MB.
- The image must be valid base64 and decode as an image.
- The image must contain a detectable face. Use a frontal, well-lit face crop when possible.
- The uploaded face is indexed for future duplicate detection and face search.
- The uploaded face is not automatically blocklisted.
List or delete uploaded faces
List profile faces:curl https://verification.didit.me/v3/organization/$ORGANIZATION_ID/application/$APPLICATION_ID/vendor-users/by-id/$DIDIT_INTERNAL_ID/faces/ \
-H "x-api-key: YOUR_API_KEY"
curl -X DELETE https://verification.didit.me/v3/organization/$ORGANIZATION_ID/application/$APPLICATION_ID/vendor-users/by-id/$DIDIT_INTERNAL_ID/faces/$FACE_UUID/ \
-H "x-api-key: YOUR_API_KEY"
Permissions
Use an API key for the same application. The key must belong to an app allowed to manage the target User profile.Failure modes
400— invalid base64, invalid image, no detectable face, image over 2 MB, or the User already has 5 uploaded faces.401— missing or invalid credentials.403— API key is valid but not allowed to manage this User profile.404— no User exists for thatdidit_internal_idin the application.429— rate-limited; back off usingRetry-After.
Related
Authorizations
Path Parameters
Organization UUID that owns the application.
Application UUID that owns the User profile.
Didit's internal User UUID, returned as didit_internal_id by GET /v3/users/{vendor_data}/ and POST /v3/users/create/.
Body
Response
Face uploaded and attached to the User profile.
UUID of the uploaded User face record.
Signed URL for the uploaded face image.
Comment supplied when the face was uploaded.
Email or actor identifier of the uploader when available.
Upload timestamp.