> ## 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.

# 年龄估算 API：基于自拍的年龄验证

> Didit 提供 AI 年龄估算 API（POST /v3/age-estimation/），内置被动活体检测，无需证件，推理耗时低于 2 秒，按次付费。



## OpenAPI

````yaml zh/openapi-25.json POST /v3/age-estimation/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: 身份证件验证 API。使用 x-api-key 请求头进行身份验证。
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/age-estimation/:
    post:
      tags:
        - Standalone APIs
      summary: 年龄估算（人脸年龄 + 被动活体检测）
      description: >-
        通过单张人脸照片估算人员年龄，并在同一次调用中执行被动活体检测：返回模型预测的 `age_estimation`（以岁为单位）、活体检测
        `score`（0–100）以及 `Approved`/`Declined` 的
        `status`。该年龄是**根据人脸由模型预测得出，而非通过证件核验**。可将其用于年龄门槛和低摩擦检查，但不能作为年龄的法律证明。


        **工作原理。**系统会分析图像中的人脸（如果拍摄的人脸可能是横向或倒置的，请设置
        `rotate_image=true`）；检测到的每张人脸都会获得一个估算年龄，画面中最大的人脸决定
        `age_estimation`。与此同时，被动活体检测模型会评估照片是否为真人（无需用户配合动作验证），并检测呈现攻击（翻拍照、屏幕、面具）。为获得最佳效果，每张图像请提交一张清晰、正面、光线充足的人脸。


        **决策逻辑。**出现任何警告都会导致拒绝：仅当 `warnings` 数组为空时，`status` 才为 `Approved`。活体检测
        `score` 低于或等于 `face_liveness_score_decline_threshold`（默认 `30`）会添加
        `LOW_LIVENESS_SCORE`；检测到攻击会添加 `LIVENESS_FACE_ATTACK`；活体检测模型未检测到人脸会添加
        `NO_FACE_DETECTED`；无法估算人脸年龄会添加 `AGE_NOT_DETECTED`（`age_estimation` 为
        `null`）；估算年龄低于 `age_estimation_decline_threshold`（默认 `18`）会添加
        `AGE_BELOW_MINIMUM`。对于接近您阈值的临界年龄，建议回退到基于证件的验证，因为模型对接近边界的人脸误差会增加。


        **计费。**每次 `200` 响应将消耗一个年龄估算 API
        额度（从您的套餐额度或充值余额中扣除）。当组织的余额不足以支付此次调用时，endpoint 会在进行任何图像处理之前返回 `403`
        及额度不足错误。


        **会话持久化（`save_api_request`，默认 `true`）。**当为 `true` 时，该调用将作为 API
        类型的会话进行持久化：它会显示在 Business Console 中，返回的 `request_id` 是真实的会话 ID，您可以将其传递给
        `GET /v3/session/{sessionId}/decision/`（结果在其中的 `liveness_checks[]`
        中公开，且带有 `features:
        ["AGE_ESTIMATION"]`），人脸裁剪图和参考图像将被存储，人脸特征向量会被添加到您应用的人脸索引中（供人脸搜索和重复项检测使用），并触发
        `status.updated` Webhook。当为 `false` 时，不会存储任何内容，且 `request_id` 是一次性关联
        UUID，后续无法查询。


        **沙盒。**沙盒 API 密钥会跳过所有处理和计费：在请求验证后（格式错误的输入仍会返回 `400`），endpoint 会返回静态的
        `Approved` 模拟 payload（`age_estimation: 30`，无警告），不会持久化任何会话，也不会消耗任何额度。


        **认证。**在 `x-api-key` 请求头中发送您应用的 API 密钥。缺少或无效的凭据将返回 `403`（`{"detail":
        "You do not have permission to perform this action."}`），此 API 从不返回
        `401`。


        **速率限制。**所有 POST/PATCH/DELETE endpoint 共享每个 API 密钥 300 次请求/分钟的写入预算；超出将返回
        `429`。
      operationId: post_v3age-estimation
      parameters: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - user_image
              properties:
                user_image:
                  type: string
                  format: binary
                  description: >-
                    要分析的人脸照片（例如自拍照）。请提交一张拍摄对象面部清晰可见且光线充足的正面照片。允许的文件扩展名：`tiff`、`jpg`、`jpeg`、`png`、`webp`（不支持
                    PDF）。最大上传大小：**5 MB**（较大文件将被拒绝并返回 `400`）。图像在处理前会自动压缩至约 0.3
                    MB，因此极高的分辨率并不会提高准确性。
                face_liveness_score_decline_threshold:
                  type: number
                  format: float
                  default: 30
                  minimum: 0
                  maximum: 100
                  description: >-
                    活体阈值（0–100）。活体 `score` **达到或低于**此值将添加 `LOW_LIVENESS_SCORE`
                    警告并予以拒绝。调高此值可实施更严格的防欺骗攻击策略；超出 0–100 范围的值将返回 `400`。
                  example: 30
                age_estimation_decline_threshold:
                  type: integer
                  default: 18
                  minimum: 0
                  maximum: 100
                  description: >-
                    可接受的最低估算年龄（周岁）。估算年龄**低于**该值将添加 `AGE_BELOW_MINIMUM`
                    警告并予以拒绝。设为 `0` 可禁用年龄检查（此时调用仅执行活体检测 + 年龄估算，不做出基于年龄的决策）。
                  example: 18
                rotate_image:
                  type: boolean
                  default: false
                  description: >-
                    为 `true` 时，服务会按 90
                    度递增（0、90、180、270）尝试输入图像，并使用人脸检测效果最佳的方向，这对于缺少 EXIF
                    方向信息的移动端拍摄非常有用。会增加延迟，因此仅在您无法保证图像为正向时启用。
                  example: false
                save_api_request:
                  type: boolean
                  default: true
                  description: >-
                    为 `true`（默认）时，将此次调用持久化为 API 类型的会话，在 Business Console
                    中可见，可使用返回的 `request_id` 通过 `GET
                    /v3/session/{sessionId}/decision/` 检索，通过 `status.updated`
                    Webhook 发出通知，并将检测到的人脸添加到您应用的人脸索引中。为 `false` 时，不存储任何内容，且
                    `request_id` 仅为用于关联响应的临时 UUID。
                  example: true
                vendor_data:
                  type: string
                  description: >-
                    可选的不透明字符串（您的内部用户 ID、邮箱、UUID 等），存储在持久化会话中并在响应中回显。可用于将 API
                    调用与您自己的记录相关联，并在稍后筛选会话。
                  example: user-123
                metadata:
                  type: object
                  additionalProperties: true
                  description: >-
                    与会话一同存储（当 `save_api_request=true` 时）并在响应中原样返回的可选 JSON 对象。在
                    multipart 请求中，请将其作为 JSON 编码的字符串字段发送（例如
                    `metadata={"flow":"age-gate"}`），它会被解析为对象。
                  example:
                    flow: age-gate
            example:
              user_image: (binary JPEG/PNG of the selfie)
              face_liveness_score_decline_threshold: 30
              age_estimation_decline_threshold: 18
              rotate_image: false
              save_api_request: true
              vendor_data: user-123
              metadata:
                flow: age-gate
      responses:
        '200':
          description: >-
            年龄估算和被动活体检测已完成。`age_estimation.age_estimation`
            是模型预测的最大检测人脸年龄（以岁为单位，未检测到则为 `null`）；`age_estimation.score`
            是被动活体检测分数（0–100）；仅当 `warnings` 为空时，`status` 才为
            `Approved`。未成年或欺骗攻击的抓拍仍会返回 `200` 及 `status: "Declined"`，请检查响应体，而不仅仅是
            HTTP 状态码。当 `save_api_request=true` 时，`request_id` 为持久化的会话 ID。
          content:
            application/json:
              examples:
                Approved:
                  summary: 活体成人面部 — 两项检查均已通过
                  value:
                    request_id: 0c40ba43-64ab-4e2e-b4b8-7d1f12f81bc1
                    age_estimation:
                      status: Approved
                      method: PASSIVE
                      score: 97.5
                      user_image:
                        entities:
                          - age: 27.33
                            bbox:
                              - 40
                              - 40
                              - 100
                              - 100
                            confidence: 0.7177750468254089
                            gender: male
                        best_angle: 0
                      age_estimation: 27.33
                      warnings: []
                    vendor_data: user-123
                    metadata:
                      flow: age-gate
                    created_at: '2026-06-12T02:24:11.512941+00:00'
                Declined - age below threshold:
                  summary: 估算年龄低于 `age_estimation_decline_threshold`
                  value:
                    request_id: 9be41a6f-2f4e-4f57-92f4-b3a4f6f0a1c2
                    age_estimation:
                      status: Declined
                      method: PASSIVE
                      score: 95
                      user_image:
                        entities:
                          - age: 16.5
                            bbox:
                              - 40
                              - 40
                              - 100
                              - 100
                            confidence: 0.7177750468254089
                            gender: female
                        best_angle: 0
                      age_estimation: 16.5
                      warnings:
                        - risk: AGE_BELOW_MINIMUM
                          feature: LIVENESS
                          additional_data: null
                          log_type: error
                          short_description: Age below minimum
                          long_description: >-
                            The age of the face is below the minimum age
                            threshold for the application.
                    vendor_data: user-123
                    metadata: null
                    created_at: '2026-06-12T02:26:40.118332+00:00'
                Declined - liveness too low:
                  summary: 活体评分达到或低于拒绝阈值（疑似欺骗攻击）
                  value:
                    request_id: 5f6f2f1f-7c4f-43b9-8d62-0a8f4c2d9e77
                    age_estimation:
                      status: Declined
                      method: PASSIVE
                      score: 5
                      user_image:
                        entities:
                          - age: 25
                            bbox:
                              - 40
                              - 40
                              - 100
                              - 100
                            confidence: 0.7177750468254089
                            gender: male
                        best_angle: 0
                      age_estimation: 25
                      warnings:
                        - risk: LOW_LIVENESS_SCORE
                          feature: LIVENESS
                          additional_data: null
                          log_type: error
                          short_description: Low liveness score
                          long_description: >-
                            The liveness check resulted in a low score,
                            indicating potential use of non-live facial
                            representations or poor-quality biometric data.
                    vendor_data: user-123
                    metadata: null
                    created_at: '2026-06-12T02:27:02.901547+00:00'
              schema:
                type: object
                properties:
                  request_id:
                    type: string
                    format: uuid
                    description: >-
                      当 `save_api_request=true` 时持久化的会话 ID（可用于 `GET
                      /v3/session/{sessionId}/decision/`）；否则为一个临时的关联 UUID。
                  age_estimation:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - Approved
                          - Declined
                        description: >-
                          未触发任何警告时为 `Approved`；否则为 `Declined`（该 endpoint
                          产生的所有警告均会导致拒绝）。
                      method:
                        type: string
                        enum:
                          - PASSIVE
                        description: 活体检测方法。在此 endpoint 上始终为 `PASSIVE`（单张图像，无用户挑战）。
                      score:
                        type: number
                        format: float
                        nullable: true
                        minimum: 0
                        maximum: 100
                        description: >-
                          0 到 100 之间的静默活体评分，即模型对照片显示为活人的置信度。与
                          `face_liveness_score_decline_threshold`
                          进行比对；等于或低于该阈值时调用将被拒绝，并提示
                          `LOW_LIVENESS_SCORE`。当活体模型未返回置信度时为 `null`；由于在阈值比对中
                          null 被视作 0，调用仍会被拒绝并提示 `LOW_LIVENESS_SCORE`。
                        example: 97.5
                      user_image:
                        type: object
                        description: 所分析图像的人脸检测结果。
                        properties:
                          entities:
                            type: array
                            description: >-
                              每张检测到的人脸对应一个条目。未检测到人脸时为空（此时 `age_estimation` 为
                              `null` 并添加 `AGE_NOT_DETECTED` 警告）。
                            items:
                              type: object
                              properties:
                                age:
                                  type: number
                                  format: float
                                  description: 模型估算的人脸年龄（以岁为单位）。
                                  example: 27.33
                                bbox:
                                  type: array
                                  items:
                                    type: integer
                                  minItems: 4
                                  maxItems: 4
                                  description: >-
                                    检测到的人脸边界框，表示为处理后图像中的 `[x_min, y_min, x_max,
                                    y_max]` 像素坐标。
                                  example:
                                    - 40
                                    - 40
                                    - 100
                                    - 100
                                confidence:
                                  type: number
                                  format: float
                                  minimum: 0
                                  maximum: 1
                                  description: 人脸检测置信度（0–1）。
                                  example: 0.7177750468254089
                                gender:
                                  type: string
                                  description: 模型预测的检测人脸性别（`male` 或 `female`）。仅供参考。
                                  example: male
                          best_angle:
                            type: integer
                            nullable: true
                            description: >-
                              产生最佳人脸检测结果的旋转角度（度：0、90、180 或 270）。仅当
                              `rotate_image=true` 纠正了方向时才为非零值。
                            example: 0
                      age_estimation:
                        type: number
                        format: float
                        nullable: true
                        description: >-
                          模型预测的检测到的**最大**人脸的年龄（以岁为单位）。当无法估算人脸年龄时为 `null`（会添加
                          `AGE_NOT_DETECTED` 警告且调用被拒绝）。
                        example: 27.33
                      warnings:
                        type: array
                        description: 完全通过审核时为空。任何条目都会将 `status` 设置为 `Declined`。
                        items:
                          type: object
                          properties:
                            risk:
                              type: string
                              enum:
                                - NO_FACE_DETECTED
                                - LOW_LIVENESS_SCORE
                                - LIVENESS_FACE_ATTACK
                                - AGE_NOT_DETECTED
                                - AGE_BELOW_MINIMUM
                              description: >-
                                机器可读的风险代码。`NO_FACE_DETECTED`：活体检测模型未发现人脸；`LOW_LIVENESS_SCORE`：活体检测
                                `score` 低于或等于
                                `face_liveness_score_decline_threshold`；`LIVENESS_FACE_ATTACK`：检测到呈现攻击（照片/屏幕/面具）；`AGE_NOT_DETECTED`：无法估算人脸年龄；`AGE_BELOW_MINIMUM`：估算年龄低于
                                `age_estimation_decline_threshold`。`NO_FACE_DETECTED`
                                与 `LOW_LIVENESS_SCORE` 互斥，未检测到人脸时仅返回
                                `NO_FACE_DETECTED`。
                            feature:
                              type: string
                              enum:
                                - LIVENESS
                              description: 引发该警告的功能。在此 endpoint 上始终为 `LIVENESS`。
                            additional_data:
                              type: object
                              nullable: true
                              additionalProperties: true
                              description: 对于年龄估算警告始终为 `null`。
                            log_type:
                              type: string
                              enum:
                                - error
                              description: >-
                                严重程度。此 endpoint 生成的每个警告均为 `error`，并将 `status`
                                设置为 `Declined`。
                            short_description:
                              type: string
                              description: 易于阅读的单行风险摘要。
                            long_description:
                              type: string
                              description: 风险的便于人类阅读的说明。
                  vendor_data:
                    type: string
                    nullable: true
                    description: 您发送的 `vendor_data` 回显，或 `null`。
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: 您发送的 `metadata` 对象回显，或 `null`。
                  created_at:
                    type: string
                    format: date-time
                    description: 响应生成时的 ISO 8601 时间戳（UTC）。
        '400':
          description: >-
            验证错误。当 `user_image` 缺失、超过 5 MB、扩展名不受支持，或阈值超出范围时返回。响应体为 DRF
            的标准字段错误响应格式：每个有问题的字段对应一个消息数组。
          content:
            application/json:
              examples:
                Missing user image:
                  summary: 表单数据中未包含 `user_image`
                  value:
                    user_image:
                      - No file was submitted.
                Unsupported file extension:
                  summary: 文件扩展名不在 tiff/jpg/jpeg/png/webp 范围内
                  value:
                    user_image:
                      - >-
                        File extension “txt” is not allowed. Allowed extensions
                        are: tiff, jpg, jpeg, png, webp.
                File too large:
                  summary: 上传内容超过 5 MB 限制
                  value:
                    user_image:
                      - File size should not exceed 5 MB
                Threshold out of range:
                  summary: '`face_liveness_score_decline_threshold` 超出 0–100 范围'
                  value:
                    face_liveness_score_decline_threshold:
                      - Ensure this value is less than or equal to 100.
        '403':
          description: >-
            权限被拒绝。当缺少 `x-api-key` 请求头，或调用组织的余额无法覆盖此次调用时返回；错误、已撤销或已过期的密钥返回
            `401`。缺少密钥时返回 `403` 及 `{"detail": ...}`；错误、已撤销或已过期的密钥返回
            `401`。额度不足时会在进行任何图像处理之前返回 `403` 及 `{"error": ...}`。
          content:
            application/json:
              examples:
                Missing or invalid API key:
                  summary: 缺少 `x-api-key` 请求头，或者密钥无效/已被吊销
                  value:
                    detail: You do not have permission to perform this action.
                Not enough credits:
                  summary: 组织余额不足以支付本次调用
                  value:
                    error: >-
                      You don't have enough credits to perform this request.
                      Please top up at https://business.didit.me
        '429':
          description: >-
            超出速率限制。POST/PATCH/DELETE endpoint 每个 API 密钥每分钟共享 300
            次写入请求的额度（交易创建和事件摄入具有单独的 600 次额度）。响应包含
            `X-RateLimit-Limit`、`X-RateLimit-Remaining`、`X-RateLimit-Reset` 和
            `Retry-After` 响应头。
          content:
            application/json:
              examples:
                Write rate limit exceeded:
                  summary: 当前分钟内的写入请求超过 300 次
                  value:
                    detail: >-
                      Write request rate limit exceeded. You can make up to 300
                      requests per minute.
              schema:
                type: object
                properties:
                  detail:
                    type: string
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://verification.didit.me/v3/age-estimation/' \
              -H 'x-api-key: YOUR_API_KEY' \
              -F 'user_image=@./selfie.jpg' \
              -F 'age_estimation_decline_threshold=18' \
              -F 'face_liveness_score_decline_threshold=30' \
              -F 'save_api_request=true' \
              -F 'vendor_data=user-123'
        - lang: python
          label: Python
          source: |-
            from didit import Didit

            # Reads DIDIT_API_KEY.
            client = Didit()

            result = client.age_estimation.estimate(
                user_image=open("user_image.jpg", "rb"),
                face_liveness_score_decline_threshold=30.0,
                age_estimation_decline_threshold=18,
                rotate_image=False,
                save_api_request=True,
                vendor_data="user-123",
                metadata={"flow": "age-gate"},
            )
            print(result)
        - lang: javascript
          label: Node.js
          source: |-
            import Didit, { fileFromPath } from "@didit-protocol/sdk-node";

            // Reads DIDIT_API_KEY.
            const didit = new Didit();

            const result = await didit.ageEstimation.estimate({
              user_image: await fileFromPath("user_image.jpg"),
              face_liveness_score_decline_threshold: 30.0,
              age_estimation_decline_threshold: 18,
              rotate_image: false,
              save_api_request: true,
              vendor_data: "user-123",
              metadata: { flow: "age-gate" },
            });
            console.log(result);
        - lang: go
          label: Go
          source: "ctx := context.Background()\n// Reads DIDIT_API_KEY.\nclient := didit.NewClient()\n\nresult, err := client.AgeEstimation.Estimate(ctx, didit.AgeEstimationEstimateParams{\n\tUserImage:                         didit.FileFromPath(\"user_image.jpg\"),\n\tFaceLivenessScoreDeclineThreshold: didit.Float(30.0),\n\tAgeEstimationDeclineThreshold:     didit.Int(18),\n\tRotateImage:                       didit.Bool(false),\n\tSaveAPIRequest:                    didit.Bool(true),\n\tVendorData:                        didit.String(\"user-123\"),\n\tMetadata:                          didit.Some(map[string]any{\"flow\": \"age-gate\"}),\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", result)"
        - lang: java
          label: Java
          source: >-
            import java.nio.file.Path;

            import java.util.Map;

            import me.didit.Didit;

            import me.didit.types.AgeEstimationEstimateParams;


            // Reads DIDIT_API_KEY.

            Didit client = new Didit();


            var result =
            client.ageEstimation().estimate(AgeEstimationEstimateParams.builder()
                    .userImage(Path.of("user_image.jpg"))
                    .faceLivenessScoreDeclineThreshold(30.0)
                    .ageEstimationDeclineThreshold(18L)
                    .rotateImage(false)
                    .saveApiRequest(true)
                    .vendorData("user-123")
                    .metadata(Map.of("flow", "age-gate"))
                    .build());
            System.out.println(result);
        - lang: php
          label: PHP
          source: |-
            <?php

            require 'vendor/autoload.php';

            use Didit\DiditClient;
            use Didit\File;

            // Reads DIDIT_API_KEY.
            $didit = new DiditClient();

            $result = $didit->ageEstimation->estimate([
                'user_image' => File::fromPath('user_image.jpg'),
                'face_liveness_score_decline_threshold' => 30.0,
                'age_estimation_decline_threshold' => 18,
                'rotate_image' => false,
                'save_api_request' => true,
                'vendor_data' => 'user-123',
                'metadata' => ['flow' => 'age-gate'],
            ]);
            print_r($result->toArray());
        - lang: ruby
          label: Ruby
          source: |-
            require "didit"

            # Reads DIDIT_API_KEY.
            didit = Didit::Client.new

            result = didit.age_estimation.estimate(
              user_image: Pathname("user_image.jpg"),
              face_liveness_score_decline_threshold: 30.0,
              age_estimation_decline_threshold: 18,
              rotate_image: false,
              save_api_request: true,
              vendor_data: "user-123",
              metadata: { flow: "age-gate" }
            )
            puts result.to_h
        - lang: csharp
          label: .NET
          source: >-
            using System;

            using System.Collections.Generic;

            using System.Text.Json;

            using Didit;


            // Reads DIDIT_API_KEY.

            using var client = new DiditClient();


            var result = await client.AgeEstimation.EstimateAsync(new
            AgeEstimationEstimateParams

            {
                UserImage = FileUpload.FromPath("user_image.jpg"),
                FaceLivenessScoreDeclineThreshold = 30.0,
                AgeEstimationDeclineThreshold = 18,
                RotateImage = false,
                SaveApiRequest = true,
                VendorData = "user-123",
                Metadata = new Dictionary<string, object> { ["flow"] = "age-gate" },
            });

            Console.WriteLine(JsonSerializer.Serialize(result));
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        您的应用 API 密钥，可在 Business Console 的“开发者 -> API
        密钥”中获取。主密钥拥有完整访问权限。指定名称的密钥可设置作用域：针对每个资源设为无权限、只读或读写，限定于特定工作流或已通过的会话、限定于
        IP 地址列表，以及设置到期日期。401 表示密钥错误、已撤销或已过期；403 表示未发送密钥、密钥无权访问该资源或操作，或请求来自其 IP
        列表之外的地址；在会话路由上返回 404 表示该会话不在该密钥允许的工作流或状态范围内。没有媒体访问权限的密钥获取到的图片、视频和 PDF
        URL 将为 null；没有会话写入权限的密钥获取到的会话链接和 token 将为 null。请参阅
        https://docs.didit.me/console/api-keys。

````

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