curl -X POST 'https://verification.didit.me/v3/face-search/' \
-H 'x-api-key: YOUR_API_KEY' \
-F 'user_image=@./selfie.jpg' \
-F 'search_type=most_similar' \
-F 'save_api_request=true' \
-F 'vendor_data=user-123'from didit import Didit
# Reads DIDIT_API_KEY.
client = Didit()
result = client.face_search.search(
user_image=open("user_image.jpg", "rb"),
search_type="most_similar",
rotate_image=False,
save_api_request=True,
vendor_data="user-123",
metadata={"flow": "dedup_check"},
)
print(result)import Didit, { fileFromPath } from "@didit-protocol/sdk-node";
// Reads DIDIT_API_KEY.
const didit = new Didit();
const result = await didit.faceSearch.search({
user_image: await fileFromPath("user_image.jpg"),
search_type: "most_similar",
rotate_image: false,
save_api_request: true,
vendor_data: "user-123",
metadata: { flow: "dedup_check" },
});
console.log(result);ctx := context.Background()
// Reads DIDIT_API_KEY.
client := didit.NewClient()
result, err := client.FaceSearch.Search(ctx, didit.FaceSearchSearchParams{
UserImage: didit.FileFromPath("user_image.jpg"),
SearchType: didit.Some(didit.FaceSearchSearchParamsSearchType("most_similar")),
RotateImage: didit.Bool(false),
SaveAPIRequest: didit.Bool(true),
VendorData: didit.String("user-123"),
Metadata: didit.Some(map[string]any{"flow": "dedup_check"}),
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", result)import java.nio.file.Path;
import java.util.Map;
import me.didit.Didit;
import me.didit.types.FaceSearchSearchParams;
// Reads DIDIT_API_KEY.
Didit client = new Didit();
var result = client.faceSearch().search(FaceSearchSearchParams.builder()
.userImage(Path.of("user_image.jpg"))
.searchType(FaceSearchSearchParams.SearchType.of("most_similar"))
.rotateImage(false)
.saveApiRequest(true)
.vendorData("user-123")
.metadata(Map.of("flow", "dedup_check"))
.build());
System.out.println(result);<?php
require 'vendor/autoload.php';
use Didit\DiditClient;
use Didit\File;
// Reads DIDIT_API_KEY.
$didit = new DiditClient();
$result = $didit->faceSearch->search([
'user_image' => File::fromPath('user_image.jpg'),
'search_type' => 'most_similar',
'rotate_image' => false,
'save_api_request' => true,
'vendor_data' => 'user-123',
'metadata' => ['flow' => 'dedup_check'],
]);
print_r($result->toArray());require "didit"
# Reads DIDIT_API_KEY.
didit = Didit::Client.new
result = didit.face_search.search(
user_image: Pathname("user_image.jpg"),
search_type: "most_similar",
rotate_image: false,
save_api_request: true,
vendor_data: "user-123",
metadata: { flow: "dedup_check" }
)
puts result.to_husing System;
using System.Collections.Generic;
using System.Text.Json;
using Didit;
// Reads DIDIT_API_KEY.
using var client = new DiditClient();
var result = await client.FaceSearch.SearchAsync(new FaceSearchSearchParams
{
UserImage = FileUpload.FromPath("user_image.jpg"),
SearchType = new FaceSearchSearchParamsSearchType("most_similar"),
RotateImage = false,
SaveApiRequest = true,
VendorData = "user-123",
Metadata = new Dictionary<string, object> { ["flow"] = "dedup_check" },
});
Console.WriteLine(JsonSerializer.Serialize(result));{
"request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"face_search": {
"status": "Declined",
"total_matches": 1,
"matches": [
{
"session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
"session_number": 323442,
"similarity_percentage": 99.99,
"source": "session",
"vendor_data": "user-1",
"verification_date": "2025-01-01T00:00:00Z",
"user_details": {
"full_name": "Jane Marie Doe",
"document_type": "ID",
"document_number": "X1234567"
},
"match_image_url": "https://<media-host>/face/3f6a1c2e/reference.jpg",
"status": "Approved",
"is_blocklisted": true,
"is_allowlisted": false,
"api_service": null,
"vendor_user_id": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
"biometric_template_id": null
}
],
"user_image": {
"entities": [
{
"bbox": [
40,
40,
120,
120
],
"confidence": 0.732973
}
],
"best_angle": 0
},
"warnings": [
{
"risk": "FACE_IN_BLOCKLIST",
"feature": "LIVENESS",
"additional_data": {
"blocklisted_session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
"blocklisted_session_number": 323442,
"api_service": null
},
"log_type": "error",
"short_description": "Face in blocklist",
"long_description": "The system identified a face in the blocklist, which means the face is not allowed to be verified."
}
]
},
"vendor_data": "user-123",
"metadata": null,
"created_at": "2026-06-12T01:04:42.763237+00:00"
}Face Search API: 1:N Facial Dedup & Fraud Rings
POST /v3/face-search/ for 1:N face search across verified users. Detect duplicates, fraud rings, and re-auth. Sub-2s inference, pay-per-call, no contracts.
curl -X POST 'https://verification.didit.me/v3/face-search/' \
-H 'x-api-key: YOUR_API_KEY' \
-F 'user_image=@./selfie.jpg' \
-F 'search_type=most_similar' \
-F 'save_api_request=true' \
-F 'vendor_data=user-123'from didit import Didit
# Reads DIDIT_API_KEY.
client = Didit()
result = client.face_search.search(
user_image=open("user_image.jpg", "rb"),
search_type="most_similar",
rotate_image=False,
save_api_request=True,
vendor_data="user-123",
metadata={"flow": "dedup_check"},
)
print(result)import Didit, { fileFromPath } from "@didit-protocol/sdk-node";
// Reads DIDIT_API_KEY.
const didit = new Didit();
const result = await didit.faceSearch.search({
user_image: await fileFromPath("user_image.jpg"),
search_type: "most_similar",
rotate_image: false,
save_api_request: true,
vendor_data: "user-123",
metadata: { flow: "dedup_check" },
});
console.log(result);ctx := context.Background()
// Reads DIDIT_API_KEY.
client := didit.NewClient()
result, err := client.FaceSearch.Search(ctx, didit.FaceSearchSearchParams{
UserImage: didit.FileFromPath("user_image.jpg"),
SearchType: didit.Some(didit.FaceSearchSearchParamsSearchType("most_similar")),
RotateImage: didit.Bool(false),
SaveAPIRequest: didit.Bool(true),
VendorData: didit.String("user-123"),
Metadata: didit.Some(map[string]any{"flow": "dedup_check"}),
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", result)import java.nio.file.Path;
import java.util.Map;
import me.didit.Didit;
import me.didit.types.FaceSearchSearchParams;
// Reads DIDIT_API_KEY.
Didit client = new Didit();
var result = client.faceSearch().search(FaceSearchSearchParams.builder()
.userImage(Path.of("user_image.jpg"))
.searchType(FaceSearchSearchParams.SearchType.of("most_similar"))
.rotateImage(false)
.saveApiRequest(true)
.vendorData("user-123")
.metadata(Map.of("flow", "dedup_check"))
.build());
System.out.println(result);<?php
require 'vendor/autoload.php';
use Didit\DiditClient;
use Didit\File;
// Reads DIDIT_API_KEY.
$didit = new DiditClient();
$result = $didit->faceSearch->search([
'user_image' => File::fromPath('user_image.jpg'),
'search_type' => 'most_similar',
'rotate_image' => false,
'save_api_request' => true,
'vendor_data' => 'user-123',
'metadata' => ['flow' => 'dedup_check'],
]);
print_r($result->toArray());require "didit"
# Reads DIDIT_API_KEY.
didit = Didit::Client.new
result = didit.face_search.search(
user_image: Pathname("user_image.jpg"),
search_type: "most_similar",
rotate_image: false,
save_api_request: true,
vendor_data: "user-123",
metadata: { flow: "dedup_check" }
)
puts result.to_husing System;
using System.Collections.Generic;
using System.Text.Json;
using Didit;
// Reads DIDIT_API_KEY.
using var client = new DiditClient();
var result = await client.FaceSearch.SearchAsync(new FaceSearchSearchParams
{
UserImage = FileUpload.FromPath("user_image.jpg"),
SearchType = new FaceSearchSearchParamsSearchType("most_similar"),
RotateImage = false,
SaveApiRequest = true,
VendorData = "user-123",
Metadata = new Dictionary<string, object> { ["flow"] = "dedup_check" },
});
Console.WriteLine(JsonSerializer.Serialize(result));{
"request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"face_search": {
"status": "Declined",
"total_matches": 1,
"matches": [
{
"session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
"session_number": 323442,
"similarity_percentage": 99.99,
"source": "session",
"vendor_data": "user-1",
"verification_date": "2025-01-01T00:00:00Z",
"user_details": {
"full_name": "Jane Marie Doe",
"document_type": "ID",
"document_number": "X1234567"
},
"match_image_url": "https://<media-host>/face/3f6a1c2e/reference.jpg",
"status": "Approved",
"is_blocklisted": true,
"is_allowlisted": false,
"api_service": null,
"vendor_user_id": "2f7c1a9e-8b4d-4c6a-9e1f-3d5b7a9c1e2f",
"biometric_template_id": null
}
],
"user_image": {
"entities": [
{
"bbox": [
40,
40,
120,
120
],
"confidence": 0.732973
}
],
"best_angle": 0
},
"warnings": [
{
"risk": "FACE_IN_BLOCKLIST",
"feature": "LIVENESS",
"additional_data": {
"blocklisted_session_id": "882c42d5-8a4d-4d20-8080-a22f57822c86",
"blocklisted_session_number": 323442,
"api_service": null
},
"log_type": "error",
"short_description": "Face in blocklist",
"long_description": "The system identified a face in the blocklist, which means the face is not allowed to be verified."
}
]
},
"vendor_data": "user-123",
"metadata": null,
"created_at": "2026-06-12T01:04:42.763237+00:00"
}Authorizations
Your application's API key, from Developers -> API keys in the Business Console. The primary key has full access. A named key can be scoped: none, read or write per resource, limited to some workflows or to approved sessions, to a list of IP addresses, and to an expiry date. 401 means the key is wrong, revoked or expired; 403 means no key was sent, the key has no access to this resource or action, or the request came from an address outside its IP list; 404 on a session route means the session is outside the key's workflows or statuses. A key without media access receives image, video and PDF URLs as null, and a key without sessions write receives session links and tokens as null. See https://docs.didit.me/console/api-keys.
Body
Front-facing face image to search with. Allowed extensions: tiff, jpg, jpeg, png, webp. Maximum upload size: 5 MB (larger files are rejected with 400). Images are automatically compressed to ~0.5 MB before processing, so very high resolutions do not improve accuracy. The image must contain at least one detectable face — otherwise the endpoint returns 400. When several faces are present, the largest one is searched and a MULTIPLE_FACES_DETECTED warning is added.
Search policy. most_similar (default) ranks every enrolled face in your application by similarity. blocklisted_or_approved restricts candidates to blocklisted faces, allowlisted faces, faces from approved sessions, and imported user-profile faces — with blocklisted entries ranked first.
most_similar, blocklisted_or_approved "most_similar"
When true (default), persists the call as an API-type session, emits a status.updated webhook, presigns match_image_url values, and enrolls the searched face into your face search index (Face Search enrollments are excluded from future searches). When false, the search is one-shot — no session is stored and the face is not enrolled.
true
Response
Face search completed. face_search.matches holds up to 5 similar faces ordered by similarity; an empty array means no enrolled face exceeded the similarity floor. status is Declined only on blocklist hits — duplicate matches alone return Approved, so inspect matches and warnings, not just status. When save_api_request=true, request_id is the persisted session id. Each match carries source (session, imported, list_entry, or retained_template), vendor_user_id, and biometric_template_id; a retained_template match comes from an image-free biometric template kept after the source session was deleted and has null session fields, match_image_url, and user_details.