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'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)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);ctx := context.Background()
// Reads DIDIT_API_KEY.
client := didit.NewClient()
result, err := client.AgeEstimation.Estimate(ctx, didit.AgeEstimationEstimateParams{
UserImage: didit.FileFromPath("user_image.jpg"),
FaceLivenessScoreDeclineThreshold: didit.Float(30.0),
AgeEstimationDeclineThreshold: didit.Int(18),
RotateImage: didit.Bool(false),
SaveAPIRequest: didit.Bool(true),
VendorData: didit.String("user-123"),
Metadata: didit.Some(map[string]any{"flow": "age-gate"}),
})
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.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);<?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());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_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.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));{
"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"
}Age Estimation API: Selfie-Based Age Verification
POST /v3/age-estimation/ for AI-powered age estimation with built-in passive liveness. No ID required, sub-2s inference, pay-per-use pricing.
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'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)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);ctx := context.Background()
// Reads DIDIT_API_KEY.
client := didit.NewClient()
result, err := client.AgeEstimation.Estimate(ctx, didit.AgeEstimationEstimateParams{
UserImage: didit.FileFromPath("user_image.jpg"),
FaceLivenessScoreDeclineThreshold: didit.Float(30.0),
AgeEstimationDeclineThreshold: didit.Int(18),
RotateImage: didit.Bool(false),
SaveAPIRequest: didit.Bool(true),
VendorData: didit.String("user-123"),
Metadata: didit.Some(map[string]any{"flow": "age-gate"}),
})
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.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);<?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());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_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.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));{
"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"
}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
Face photo to analyze (e.g. a selfie). Submit a single front-facing photo with the subject's face clearly visible and well lit. Allowed extensions: tiff, jpg, jpeg, png, webp (no PDF). Maximum upload size: 5 MB (larger files are rejected with 400). Images are automatically compressed to ~0.3 MB before processing, so very high resolutions do not improve accuracy.
Minimum acceptable estimated age in years. An estimated age below this value adds an AGE_BELOW_MINIMUM warning and declines. Set 0 to disable the age check (the call then only runs liveness + age estimation without an age-based decision).
0 <= x <= 10018
When true, the service tries the input image in 90-degree increments (0, 90, 180, 270) and uses the orientation that yields the best face detection — useful for mobile captures with missing EXIF orientation. Adds latency, so only enable it if you cannot guarantee upright images.
false
When true (default), persists the call as an API-type session — visible in the Business Console, retrievable via GET /v3/session/{sessionId}/decision/ using the returned request_id, announced through a status.updated webhook, and with the detected face added to your application's face index. When false, nothing is stored and request_id is a transient UUID for response correlation only.
true
Response
Age estimation and passive liveness completed. age_estimation.age_estimation is the model-predicted age in years of the largest detected face (null if none); age_estimation.score is the passive-liveness score (0–100); status is Approved only when warnings is empty. An underage or spoofed capture still returns 200 with status: "Declined" — inspect the body, not just the HTTP code. When save_api_request=true, request_id is the persisted session id.