Upload faces for duplicate detection enrollment
curl --request POST \
--url https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'images=<string>' \
--form images.items='@example-file'import requests
url = "https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces"
files = { "images.items": ("example-file", open("example-file", "rb")) }
payload = { "images": "<string>" }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('images', '<string>');
form.append('images.items', '{
"fileName": "example-file"
}');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Face upload accepted and queued for duplicate detection enrollment",
"data": {
"uploadId": "3aa8f48e-8a62-4439-82b9-bc3ae4b176a2",
"trustFlowId": 409,
"numberOfImages": 12,
"status": 1,
"statusLabel": "Processing"
}
}Duplicate Detection
Upload faces for duplicate detection enrollment
Mass-enroll up to 50 face images into the duplicate-detection watchlist in one asynchronous batch.
POST
/
api
/
v3
/
duplicate-detection
/
faces
Upload faces for duplicate detection enrollment
curl --request POST \
--url https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'images=<string>' \
--form images.items='@example-file'import requests
url = "https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces"
files = { "images.items": ("example-file", open("example-file", "rb")) }
payload = { "images": "<string>" }
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('images', '<string>');
form.append('images.items', '{
"fileName": "example-file"
}');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://{environment-subdomain}.idmetagroup.com/api/v3/duplicate-detection/faces")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"images.items\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Face upload accepted and queued for duplicate detection enrollment",
"data": {
"uploadId": "3aa8f48e-8a62-4439-82b9-bc3ae4b176a2",
"trustFlowId": 409,
"numberOfImages": 12,
"status": 1,
"statusLabel": "Processing"
}
}Mass-enrolls up to 50 face images into the reserved biometric duplicate-detection watchlist in one call. Each image is processed asynchronously: a Trust Validation is created for it, the face is enrolled against the engine, and — only if enrollment succeeds — the image is stored and the Trust Validation is marked Verified.
This lets you pre-seed the duplicate-detection watchlist in bulk (for example, when migrating an existing customer base) instead of enrolling one face per live verification.
Processing is asynchronous. This endpoint queues the batch and returns immediately (
Example form fields:
The
Transient — safe to retry.
202). Poll GET /api/v3/duplicate-detection/uploads/{uploadId} for progress and per-image results.
Authentication
Same as all other v3 endpoints:- Bearer token (Sanctum) in the
Authorizationheader - HMAC signature headers (
X-HMAC-SIGNATURE,X-TIMESTAMP,X-USER-ID)
Request
Content-Type:multipart/form-data
| Field | Type | Required | Notes |
|---|---|---|---|
images | array of files | Yes | 1–50 files (configurable batch size, default 50) |
images[] | file | Yes | jpg, jpeg, or png only; max 10 MB each (configurable) |
images[0], images[1], images[2], …
Example cURL
curl -X POST https://api.idmetagroup.com/api/v3/duplicate-detection/faces \
-H "Authorization: Bearer {token}" \
-F "images[0]=@face1.jpg" \
-F "images[1]=@face2.jpg"
Responses
202 Accepted — batch queued
{
"success": true,
"message": "Face upload accepted and queued for duplicate detection enrollment",
"data": {
"uploadId": "3aa8f48e-8a62-4439-82b9-bc3ae4b176a2",
"trustFlowId": 409,
"numberOfImages": 12,
"status": 1,
"statusLabel": "Processing"
}
}
| Field | Description |
|---|---|
uploadId | Pass this to the polling endpoint. |
trustFlowId | The internal system Trust Flow all resulting Trust Validations belong to (informational). |
status / statusLabel | The batch is always Processing (1) immediately after submission. |
422 Validation error (bad file count / type / size)
{
"success": false,
"message": "Validation error",
"errors": {
"images": ["The images must not have more than 50 items."]
}
}
errors object follows the standard Laravel validation error shape. Keys are images or images.0, images.1, etc.
422 Company storage not configured
{
"success": false,
"message": "Company storage is not configured"
}
422 Biometrics Registration not enabled
{
"success": false,
"message": "Biometrics Registration is not enabled for this company"
}
503 Queue unavailable
{
"success": false,
"message": "Enrollment queue is unavailable. Please retry shortly."
}
Behavioral notes
- Billing: This endpoint is free. No plan credit is consumed per image, unlike the single-image Biometrics Detection endpoint.
- Screening: Images are enrolled only. They are not screened against other watchlists at upload time — no duplicate or blacklist match results are returned here.
- Per-image failures: If enrollment fails (poor quality, no face detected, etc.), no Trust Validation or image is kept for that image. The failure is reported via the polling endpoint with a human-readable reason.
- Successful enrollments: Each enrolled face gets a real Trust Validation that appears in your normal Trust Validations list and can later be matched against by other verifications that screen the duplicate-detection watchlist.
Error responses
| Code | When |
|---|---|
202 | Batch queued successfully |
422 | Validation error (file count, type, or size), company storage not configured, or Biometrics Registration not enabled |
503 | Enrollment queue unavailable — retry shortly |
Authorizations
Use Bearer {your_api_token} in the Authorization header, or HMAC signature headers (X-HMAC-SIGNATURE, X-TIMESTAMP, X-USER-ID). Same authentication as other v3 endpoints.
Headers
Example:
"Bearer {your_api_token}"
Body
multipart/form-data
1–50 image files. Accepted formats: jpg, jpeg, png. Max 10 MB each. Use form fields images[0], images[1], etc.
Required array length:
1 - 50 elements
