> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# 人脸搜索 1:N 报告：匹配结果 JSON

> Didit 人脸搜索 1:N 报告参考指南：包含匹配的会话 ID、相似度百分比、黑名单标记以及用于欺诈调查的用户详情。

## 概述

人脸搜索是一种 **1:N** 生物识别搜索：Didit 会提取您 `user_image` 中检测到的最大人脸，并在您应用的人脸搜索索引中进行检索，包括从验证会话、已保存的独立 API 调用和直接上传至用户资料中录入的人脸，以及您的黑/白名单。它与 **1:1** 的人脸比对不同：人脸比对是将自拍照与特定证件上的头像进行比对，而人脸搜索则是探寻“我们之前是否在任何地方见过这个人？”。

在解析报告之前，有两项行为值得深入了解：

* **仅黑名单匹配会导致拒绝。** 仅当触发 `FACE_IN_BLOCKLIST` 或 `POSSIBLE_FACE_IN_BLOCKLIST` 警告时，`face_search.status` 才会为 `Declined`。仅存在重复匹配时仍会返回 `Approved`，请检查 `matches` 和 `warnings`，而不仅仅是 `status`。
* **可选的持久化与录入。** 当 `save_api_request=true`（默认值）时，该调用将作为 API 类型的会话持久化保存，且被搜索的人脸将被录入至您的人脸搜索索引中。通过人脸搜索调用录入的人脸**将从未来的人脸搜索结果中排除**，因此重复搜索绝不会相互匹配。如需进行一次性查询，可传入 `save_api_request=false`：此时不会存储任何内容，也不会录入人脸。

## 结果显示位置

人脸搜索是一个独立的 API。搜索结果**仅在 `POST /v3/face-search/` 响应中同步返回**，作为顶层的单个 `face_search` 对象：

```text theme={null}
POST /v3/face-search/  ──▶  { "request_id": …, "face_search": { … }, "vendor_data": …, "metadata": …, "created_at": … }
```

任何地方都不存在复数形式的 `face_searches[]` 数组：会话决策 endpoint 上用于 `id_verifications[]`、`aml_screenings[]` 和 `liveness_checks[]` 的复数数组约定在此不适用。

当 `save_api_request=true`（默认值）时，该调用还会作为 API 类型的会话持久化保存：

* **Business Console**：该会话将出现在您的会话列表中，并显示搜索图像、匹配项和警告。
* **`GET /v3/session/{sessionId}/decision/`**：可以使用返回的 `request_id` 作为会话 ID 进行检索。持久化的数据将在 `features[]` 中显示为一个 `FACE_SEARCH` 条目，并在 `liveness_checks[]` 项中携带存储的 `matches`（附带新签名的 `match_image_url` 值）和 `warnings`，而**不是**作为 `face_search` 对象呈现。

当 `save_api_request=false` 时，`request_id` 是一个临时的关联 UUID：该会话永远不会被存储，因此无法从控制台或决策 endpoint 获取。

## 数据结构

有关规范的字段表格，请参阅[数据模型参考中的人脸搜索](https://docs.didit.me/zh/reference/data-models.md#人脸搜索)。下方的结构反映了 endpoint 在运行时实际返回的内容。

```typescript theme={null}
interface FaceSearchResponse {
  request_id: string;            // UUID — the persisted session id when save_api_request=true
  face_search: {
    status: 'Approved' | 'Declined';
    total_matches: number;       // 0-5, length of matches[]
    matches: FaceSearchMatch[];  // capped at 5, ordered by similarity
    user_image: {                // always present
      entities: {
        bbox: [number, number, number, number];
        confidence: number;      // 0-1, one entry per detected face
      }[];
      best_angle: 0 | 90 | 180 | 270;
    };
    warnings: Warning[];
  };
  vendor_data: string | null;    // echoed from the request
  metadata: object | null;       // echoed from the request
  created_at: string;            // ISO 8601, e.g. "2026-06-12T01:04:42.763237+00:00"
}

interface FaceSearchMatch {
  session_id: string | null;     // UUID of the matched session; null for non-session matches
  session_number: number | null; // Console-friendly number; null for non-session matches
  similarity_percentage: number; // 0-100
  source: 'session' | 'imported' | 'list_entry' | 'retained_template';
  vendor_data: string | null;    // the matched session's, imported profile's, or retained template's User vendor_data
  vendor_user_id: string | null; // UUID of the linked User; null for list_entry matches and sessions without a User
  biometric_template_id: string | null; // set only for retained_template matches
  verification_date: string | null;  // "YYYY-MM-DDThh:mm:ssZ"; null for list_entry matches; the retention date for retained_template matches
  user_details: {
    full_name: string | null;
    document_type: string | null;
    document_number: string | null;
  } | null;                      // null when the matched session has no document data
  match_image_url: string | null; // signed URL when save_api_request=true; raw storage path otherwise; null for retained_template matches
  status: 'Approved' | 'Declined' | 'In Review' | null;  // the matched session's status
  is_blocklisted: boolean;
  is_allowlisted: boolean;
  api_service: 'ID_VERIFICATION' | 'FACE_MATCH' | 'AGE_ESTIMATION' | 'POA' | 'AML'
             | 'PASSIVE_LIVENESS' | 'DATABASE_VALIDATION' | 'PHONE_VERIFICATION'
             | 'EMAIL_VERIFICATION' | null;  // null when the match comes from a workflow session
}

interface Warning {
  risk: string;
  feature: 'LIVENESS';           // always LIVENESS on this endpoint
  additional_data: object | null;
  log_type: 'error' | 'warning' | 'information';
  short_description: string;
  long_description: string;
}
```

字段说明：

* **`matches[]` 最多包含 5 个**高于相似度底线的条目，按相似度降序排列（`search_type=blocklisted_or_approved` 会优先排列黑名单条目，其次是白名单，最后按相似度排序）。
* **`source`** 指示匹配的人脸是从何处录入的：`session`（验证会话或已保存的独立 API 调用）；`imported`（直接上传至用户资料的人脸）；`list_entry`（附加到您某个名单的人脸）；`retained_template`（应用在删除源会话后保留的不含图像的[生物特征模板](https://docs.didit.me/zh/management-api/biometric-templates/overview.md)）。对于 `imported`、`list_entry` 和 `retained_template` 匹配项，`session_id`、`session_number`、`status` 和 `api_service` 均为 `null`。
* **`retained_template` 匹配项**包含 `vendor_user_id`、`vendor_data` 和 `biometric_template_id`，而 `match_image_url`、`user_details` 以及所有与会话相关的内容始终为 `null`：生成该人脸的会话已不复存在，且该模板不包含任何图像或身份数据。对于保留的模板，`is_blocklisted` 始终为 `false`；被列入黑名单的人脸会作为 `list_entry` 匹配项单独报告。可以使用 `DELETE /v3/biometric-templates/{biometric_template_id}/` 清理该模板。
* **`api_service`** 是匹配会话的独立 API 类型（大写，例如 `PASSIVE_LIVENESS`），当匹配的人脸来自常规工作流验证会话时为 `null`。
* **`user_details`** 来自匹配会话的证件验证。对于 `source: imported` 匹配项，它将改为从用户资料中提取填充（已设置 `full_name`，`document_type`/`document_number` 为 null）；当不存在身份数据时（例如仅进行活体检测的会话），它为 `null`。
* **警告采用了简化结构**（与工作流警告相比）：其中没有 `node_id`。文档记录的响应约定（`FaceSearchResponseSerializer`）声明了五个字段：`risk`、`additional_data`、`log_type`、`short_description`、`long_description`；运行时的 payload 还会额外携带 `feature`，在此处始终为 `"LIVENESS"`。请参阅[人脸搜索警告](https://docs.didit.me/zh/core-technology/face-search/warnings-face-search.md)。
* **未排除同一用户的匹配**：与工作流重复检测不同，该独立 endpoint 不会过滤具有相同 `vendor_data` 的先前会话，因此合法老用户会与其自己早期的会话发生匹配。

## 状态值

顶层的 `face_search.status` 源自 `warnings[]`。匹配项级别的 `status` 反映了**匹配会话的**验证结果，两者相互独立。

| 值 | 出现时机 |
| - | - |
| `Approved` | 未触发黑名单警告。包含找到重复匹配项的情况：重复匹配属于信息性信号，不会导致拒绝。 |
| `Declined` | 触发了 `FACE_IN_BLOCKLIST` 或 `POSSIBLE_FACE_IN_BLOCKLIST` 警告：搜索图像与您人脸黑名单中的人脸匹配。 |

注意：当 API 未能在搜索图像中检测到人脸时，API 会在构建 `face_search` 对象**之前**返回 HTTP `400` 及 `{"error": "No face detected in the image"}`，这种情况下不存在 `Declined` 状态。额度不足时会在进行任何图像处理之前返回 HTTP `403`。

## 示例

### Approved - 重复匹配，无黑名单

```json theme={null}
{
  "request_id": "5e0c3a1f-7b2d-4c8e-9f10-2a3b4c5d6e7f",
  "face_search": {
    "status": "Approved",
    "total_matches": 1,
    "matches": [
      {
        "session_id": "1f2e3d4c-5b6a-7980-1122-334455667788",
        "session_number": 1024,
        "similarity_percentage": 87.42,
        "source": "session",
        "vendor_data": "user-9",
        "verification_date": "2025-11-20T09:15:00Z",
        "user_details": {
          "full_name": "Jane Marie Doe",
          "document_type": "Passport",
          "document_number": "X1234567"
        },
        "match_image_url": "https://<media-host>/face/9c8b7a6d/reference.jpg?signature=...",
        "status": "Approved",
        "is_blocklisted": false,
        "is_allowlisted": false,
        "api_service": null
      }
    ],
    "user_image": {
      "entities": [
        {
          "bbox": [40, 40, 120, 120],
          "confidence": 0.732973
        }
      ],
      "best_angle": 0
    },
    "warnings": [
      {
        "risk": "DUPLICATED_FACE",
        "feature": "LIVENESS",
        "additional_data": {
          "duplicated_session_id": "1f2e3d4c-5b6a-7980-1122-334455667788",
          "duplicated_session_number": 1024,
          "api_service": null
        },
        "log_type": "information",
        "short_description": "Duplicated face from other approved session",
        "long_description": "The system identified a duplicated face from another approved session, requiring further investigation."
      }
    ]
  },
  "vendor_data": "user-123",
  "metadata": null,
  "created_at": "2026-06-12T01:04:42.763237+00:00"
}
```

### Declined - 黑名单匹配

```json theme={null}
{
  "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?signature=...",
        "status": "Approved",
        "is_blocklisted": true,
        "is_allowlisted": false,
        "api_service": "PASSIVE_LIVENESS"
      }
    ],
    "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": "PASSIVE_LIVENESS"
        },
        "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"
}
```

## 相关内容

* [人脸搜索警告](https://docs.didit.me/zh/core-technology/face-search/warnings-face-search.md) — 搜索可能发出的所有警告代码
* [人脸搜索 API 参考](https://docs.didit.me/zh/standalone-apis/face-search.md) — 请求参数与 `search_type` 模式
* [数据模型 — 人脸搜索](https://docs.didit.me/zh/reference/data-models.md#人脸搜索) — 规范模式
* [Webhook](https://docs.didit.me/zh/integration/webhooks.md) — 持久化会话的 `status.updated` payload

> [!NOTE]
>
> 当 `save_api_request=true` 时，`match_image_url` 的值为带签名的短期有效 URL — 使用返回的 `request_id` 重新请求会话决策 endpoint 即可获取最新 URL。当 `save_api_request=false` 时，它们是内部存储路径，无法直接下载。请仅在您方存储匹配的会话 ID、状态以及 `similarity_percentage` — 请勿保留底层的生物特征图像。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.