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

# Age Estimation Report

> Parse Age Estimation responses: estimated age, passive liveness score, face quality metrics, decline thresholds, and warning codes. Pay-per-call from $0.10.

The Age Estimation report captures a model-predicted age (in years) for the largest face detected in an image, combined with a passive liveness check that confirms the subject is a real person rather than a photo, screen, or mask. The two checks always run together — Age Estimation never returns an age without a liveness score.

This page documents the JSON shape returned by both call paths: the standalone `POST /v3/age-estimation/` endpoint and the embedded `age_estimation` field on workflow liveness reports.

<Frame>
  <img src="https://mintcdn.com/didit-0f962782/z6T2GHM4Zh-iSj-K/images/age-estimation-report.png?fit=max&auto=format&n=z6T2GHM4Zh-iSj-K&q=85&s=f0ae767c591e55866d0cf5496291e17b" alt="Didit age estimation report with predicted age, passive liveness score and face quality metrics" width="2929" height="2028" data-path="images/age-estimation-report.png" />
</Frame>

## Overview

Age Estimation has two delivery modes:

* **Standalone API.** `POST /v3/age-estimation/` accepts a single face image (`user_image`) and returns the predicted age and passive liveness score synchronously. See the [Age Estimation standalone API reference](/standalone-apis/age-estimation).
* **Embedded in a workflow.** Every workflow liveness report carries the predicted age under `age_estimation` — the value is always populated from the largest detected face. Age thresholds are only *enforced* (raising age warnings) on age-estimation flows: adaptive age verification workflows or `AGE_ESTIMATION` workflow nodes.

Each report contains:

* The overall `status` (`Approved`, `Declined`).
* The liveness `method` (always `PASSIVE` on the standalone API; `ACTIVE_3D` / `FLASHING` / `PASSIVE` in workflows).
* A liveness `score` (0–100; higher is more confident the subject is live; `null` is treated as `0` for threshold checks).
* The predicted `age_estimation` in years (float — for example `27.33`; `null` when no face age could be estimated).
* Standalone only: a `user_image` object with an `entities[]` array (one entry per detected face — `age`, `bbox`, `confidence`, `gender`) and the `best_angle` orientation.
* Workflow only: `reference_image`, `video_url`, `matches[]`, and the passive-liveness quality metrics `face_quality` (0–100%) and `face_luminance` (0–100%). The standalone response does **not** include these fields.
* A `warnings[]` array — risk events emitted during the check (see [Age Estimation warnings](/core-technology/age-estimation/warnings-age-estimation)).

The standalone decision is `Declined` whenever `warnings` is non-empty — `Approved` requires an empty array. Warnings fire when:

* The liveness `score` is at or below `face_liveness_score_decline_threshold` (default `30`) — `LOW_LIVENESS_SCORE`.
* The predicted age is below `age_estimation_decline_threshold` (default `18`) — `AGE_BELOW_MINIMUM`. Set the threshold to `0` to disable the age check.
* No face is detected (`NO_FACE_DETECTED`) or no face age could be estimated (`AGE_NOT_DETECTED`).
* The liveness model flags a presentation attack (`LIVENESS_FACE_ATTACK`).

## Where it appears in API responses

### Standalone API — `POST /v3/age-estimation/`

The standalone response wraps the result under a single top-level `age_estimation` object, alongside `request_id` and the echoed `vendor_data` / `metadata`. When `save_api_request=true` (the default), `request_id` is the persisted session id and the result can also be fetched later from the decision endpoint; when `false`, it is a one-off correlation UUID.

```json theme={null}
{
  "request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "age_estimation": {
    "status": "Approved",
    "method": "PASSIVE",
    "score": 97.5,
    "age_estimation": 27.33,
    "user_image": { "entities": [ /* ... */ ], "best_angle": 0 },
    "warnings": []
  },
  "vendor_data": "user-123",
  "metadata": { "flow": "age-gate" },
  "created_at": "2026-06-12T02:24:11.512941+00:00"
}
```

### Workflow decision — `GET /v3/session/{session_id}/decision/`

In a workflow session, the predicted age is **embedded inside the liveness report — there is no separate age-estimation array**. The V3 decision endpoint returns liveness reports under the plural array key **`liveness_checks`** (`ReducedSessionV3DecisionSerializer.get_liveness_checks`), and each entry carries an `age_estimation` float — the estimated age of the largest detected face — or `null` if no age was computed (`LivenessV2Serializer.get_age_estimation`).

```json theme={null}
{
  "session_id": "11111111-1111-1111-1111-111111111111",
  "status": "Approved",
  "features": ["AGE_ESTIMATION"],
  "liveness_checks": [
    {
      "node_id": "feature_age_estimation_1",
      "status": "Approved",
      "method": "PASSIVE",
      "score": 89.92,
      "age_estimation": 24.3,
      "...": "..."
    }
  ]
}
```

Read the age from `liveness_checks[].age_estimation`. Persisted standalone calls (`save_api_request=true`) appear the same way on the decision endpoint, with `features` containing `AGE_ESTIMATION`.

## Schema

The canonical field-by-field schema lives on the [Data models](/reference/data-models#age-estimation) page. The standalone response shape is documented by `AgeEstimationResponseSerializer` and assembled in `AgeEstimationAPIView`; the workflow value is produced by `LivenessV3Serializer`.

```typescript theme={null}
interface AgeEstimationStandalone {
  request_id: string;                  // Session id when save_api_request=true
  age_estimation: {
    status: "Approved" | "Declined";
    method: "PASSIVE";
    score: number | null;              // Passive liveness score (0-100); null counts as 0
    age_estimation: number | null;     // Predicted age in years of the largest face (float)
    user_image: {
      entities: Array<{
        age: number;                   // Estimated age of this face
        bbox: [number, number, number, number];  // [x_min, y_min, x_max, y_max]
        confidence: number;            // Face-detection confidence (0-1)
        gender: "male" | "female";
      }>;
      best_angle: number | null;       // Rotation (0/90/180/270) with best detection
    };
    warnings: Warning[];
  };
  vendor_data: string | null;          // Echoed from the request
  metadata: object | null;             // Echoed from the request
  created_at: string;                  // ISO 8601
}

interface WorkflowLivenessWithAge {
  node_id: string | null;
  status: "Approved" | "Declined" | "In Review";
  method: "ACTIVE_3D" | "FLASHING" | "PASSIVE";
  score: number | null;                // Liveness score (0-100)
  reference_image: string;             // Presigned URL
  video_url: string | null;            // Presigned URL (active liveness only)
  age_estimation: number | null;       // Predicted age in years (float)
  face_quality: number | null;         // 0-100% (passive liveness only)
  face_luminance: number | null;       // 0-100% (passive liveness only)
  warnings: Warning[];
  matches: FaceMatch[];
}
```

### Status values

Status strings come from the shared feature-status enum (see [Status enums](/reference/data-models#status-enums)). The standalone endpoint only ever returns:

| Status     | Meaning                                                                                           |
| ---------- | ------------------------------------------------------------------------------------------------- |
| `Approved` | No warnings fired — the subject is live and the predicted age meets the configured threshold.     |
| `Declined` | At least one warning fired — low liveness score, age below threshold, no face, no age, or attack. |

In workflow sessions, the liveness check can also resolve to `In Review` when a configurable risk fires with a review action (for example `POSSIBLE_DUPLICATED_FACE`). See the [status enum reference](/reference/data-models#status-enum-reference).

## Examples

### Approved — standalone, adult subject

```json theme={null}
{
  "request_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
  "age_estimation": {
    "status": "Approved",
    "method": "PASSIVE",
    "score": 97.5,
    "age_estimation": 27.33,
    "user_image": {
      "entities": [
        { "age": 27.33, "bbox": [40, 40, 100, 100], "confidence": 0.72, "gender": "male" }
      ],
      "best_angle": 0
    },
    "warnings": []
  },
  "vendor_data": "user-123",
  "metadata": { "flow": "age-gate" },
  "created_at": "2026-06-12T02:24:11.512941+00:00"
}
```

### Declined — standalone, predicted age below threshold

```json theme={null}
{
  "request_id": "b2c3d4e5-f6a7-8901-2345-67890abcdef0",
  "age_estimation": {
    "status": "Declined",
    "method": "PASSIVE",
    "score": 92.0,
    "age_estimation": 15.8,
    "user_image": {
      "entities": [
        { "age": 15.8, "bbox": [55, 60, 110, 110], "confidence": 0.81, "gender": "female" }
      ],
      "best_angle": 0
    },
    "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-456",
  "metadata": null,
  "created_at": "2026-06-12T02:26:40.118332+00:00"
}
```

### Approved — embedded in a workflow liveness report

```json theme={null}
{
  "node_id": "feature_age_estimation_1",
  "status": "Approved",
  "method": "PASSIVE",
  "score": 89.92,
  "reference_image": "https://<media-host>/.../reference.jpg?signature=...",
  "video_url": null,
  "age_estimation": 24.3,
  "matches": [],
  "face_quality": 87.5,
  "face_luminance": 54.12,
  "warnings": []
}
```

## Security note

All image and video URLs returned in the response are pre-signed links with a limited validity window. Treat these as short-lived references — do not share them publicly, and re-call the decision endpoint to refresh expired URLs. As a best practice, store only the verification status and confidence values on your side rather than the underlying biometric media.

## Related

* [Age Estimation overview](/core-technology/age-estimation/overview) — feature behavior, pricing, decision logic.
* [Age Estimation warnings](/core-technology/age-estimation/warnings-age-estimation) — every risk code and decline trigger.
* [Standalone API reference](/standalone-apis/age-estimation) — `POST /v3/age-estimation/` request and response.
* [Data models — age estimation](/reference/data-models#age-estimation) — canonical field-by-field schema.
* [Passive liveness](/core-technology/liveness/overview) — the shared liveness model used in age-estimation responses.
