Appearance
Photo Compliance Check
Product overview: Photo compliance check.
Check an existing portrait against a document specification without generating a new image. The response is a pass or fail, a score, one result per rule, and either retake guidance or a suggestion to call another endpoint.
Field names use camelCase, the same convention as the Passport Photo API and the Fix Passport Photo API.
A passing result means the rules in this response did not fail. It is not an acceptance decision by a passport office, visa center, employer, or school. IDPhoto.ai does not claim NIST, BSI, FedRAMP, or SOC 2 certification, and this page does not publish an accuracy rate.
When to auto-fix
Read spec.alterationAllowed and fixable before you edit the photo.
United States passport photos, United Kingdom passport photos, and US Diversity Visa (DV) lottery photos must not be digitally altered. For those specifications the service returns alterationAllowed: false and fixable: false. Show retakeTips. Do not call POST /v2/aiEdit, and do not replace the background.
That matches the published rule on the pricing page: do not use the Fix Passport Photo API on a US or UK passport photograph. The US Department of State says not to upload a photo created or edited with artificial intelligence or other digital tools. UK digital photo rules say the photo must be unedited. A manipulated DV lottery photo can make the entry ineligible. See the State Department photo requirements.
For any other specification, trust the boolean in the response. Do not infer it from the country name. When fixable is true, fixSuggestion.steps names the next call. Check the result again after that call.
fixable is true only when alterationAllowed is true and every failing rule is one that the suggested endpoint can address. A closed-eye photo, a missing face, a head covering that hides the face, or a digital-alteration hint stays a retake even on a specification that otherwise allows a correction.
Before you start
You need an API key and API secret from the Dashboard. If this endpoint is not enabled on the key, contact support@idphoto.ai.
Send requests from your server. Keep both credentials out of browser code, mobile application bundles, source control, and logs. Do not log the image payload.
Choose the API region configured for your account:
| Region | Base URL |
|---|---|
| United States | https://api-us.idphotoapp.com |
| European Union | https://api-eu.idphotoapp.com |
Other regional deployments may be available on request. JSON requests use Content-Type: application/json.
Pricing for POST /v2/checkPhoto is available on request. It is not the published starting price of $0.20, which covers preparing a photo. See Pricing.
API endpoint
http
POST /v2/checkPhotoSet a client timeout of at least 60 seconds. A timeout is not proof the check was skipped. Avoid an automatic retry until you know whether a result was produced.
Request
Send exactly one image, as Base64 JSON, as an HTTPS URL, or as a multipart file.
| Field | Type | Required | Description |
|---|---|---|---|
apiKey | string | Yes | Your API key. |
apiSecret | string | Yes | Your API secret. |
imageBase64 | string | One image source | Base64-encoded JPEG or PNG, with or without a data URI prefix. |
imageUrl | string | One image source | HTTPS URL of a JPEG or PNG the service can fetch. Private, loopback, and link-local addresses are rejected. |
file | file | One image source | JPEG or PNG, only on a multipart/form-data request. |
specCode | string | Yes | Target document specification, for example us-passport. Use the same codes as the Passport Photo API. |
language | string | No | BCP 47 language for message and retakeTips, for example en or de. Defaults to en. An unknown tag falls back to English. The response language field is the language actually used. |
The uploaded file must be 10 MB or smaller. JPEG and PNG only.
specCode values are the codes in Spec Code, such as us-passport, uk-passport, us-dvlottery, and germany-passport. Confirm the live code with POST /v2/listIdPhotoSpecCode. Page slugs such as us-passport-photo are not request values.
JSON request
json
{
"apiKey": "your-api-key",
"apiSecret": "your-api-secret",
"imageBase64": "data:image/jpeg;base64,...",
"specCode": "us-passport",
"language": "en"
}To send a URL instead of Base64, omit imageBase64 and set imageUrl to an https:// address. Do not send both.
Multipart request
bash
curl --request POST \
--url https://api-us.idphotoapp.com/v2/checkPhoto \
--form 'apiKey=your-api-key' \
--form 'apiSecret=your-api-secret' \
--form 'specCode=us-passport' \
--form 'language=en' \
--form 'file=@portrait.jpg;type=image/jpeg'Response
HTTP 200 means the check ran. Read pass to see whether any rule failed. Photo problems are not HTTP errors.
| Field | Type | Description |
|---|---|---|
pass | boolean | true when no check has status fail. A warn does not fail the photo. Show warnings anyway. |
score | integer | 0 to 100, summarizing the checks on this image. It is not a probability that an authority will accept the photo. |
fixable | boolean | true only when an automated correction is allowed for this specification and every failing rule can be handed to the suggested endpoint. |
language | string | Language used for messages and retake tips. |
spec | object | Specification the check used. |
spec.specCode | string | Code you sent. |
spec.specCodeName | string | Display name from the catalog. |
spec.alterationAllowed | boolean | false for specifications that forbid a digital alteration, including background replacement. |
spec.photoSize | string | Physical size when the specification defines one. |
spec.photoPixel | string | Pixel size when the specification defines one. |
spec.backgroundColor | string | Expected background when the specification defines one. |
checks | array | One object per rule that ran. |
checks[].id | string | Stable identifier. See the table below. |
checks[].name | string | Short label for a user interface. |
checks[].status | string | pass, warn, or fail. |
checks[].measured | string or null | What was measured. null when the rule is qualitative or could not be measured. |
checks[].expected | string or null | What the specification asks for. |
checks[].message | string | Sentence you can show, in the response language. |
fixSuggestion | object or null | null when fixable is false. |
fixSuggestion.summary | string | What to do next. |
fixSuggestion.steps | array | Ordered calls. Each step has endpoint and reason. |
retakeTips | array of strings | Empty when the photo passed. Otherwise, capture instructions. |
Check identifiers
id | What it covers |
|---|---|
face_detected | A single usable face. Other rules are not measured when this fails. |
size_dimensions | Pixel size, physical size, and crop against the specification. |
head_size_position | Head height and position in the frame, including a turned or tilted head. |
background | Background color and whether it is uniform, with no objects or texture. |
lighting_shadows | Even light on the face, and shadows on the face or behind the head. |
glasses_glare | Glasses where the specification refuses them, sunglasses, and glare on the lenses. |
expression | Neutral expression and a closed mouth, when the specification asks for that. |
eyes | Eyes open and looking at the camera. |
focus | Focus and blur. |
compression_resolution | Resolution, file size, and heavy compression. |
head_covering | Head coverings. A religious or medical covering that leaves the face visible is a warn for a person to review, not an instruction to remove it. |
digital_alteration | Hints of a morph, a generated face, or a retouch that changes the person. Ordinary crop and background processing are not a fail on a specification that allows them. |
These rules follow the kinds of requirements published in ICAO 9303, ISO/IEC 19794-5, and ISO/IEC 29794-5, applied to the selected specification. Citing those standards is not a claim that this service is certified against them.
digital_alteration is a hint on this call. A separate early-access screen for AI generation or AI editing is described on the AI photo detection page. Neither result is a government decision.
US passport example
This payload is illustrative. alterationAllowed is false, so the client shows retake tips and does not call the fix endpoint.
json
{
"pass": false,
"score": 64,
"fixable": false,
"language": "en",
"spec": {
"specCode": "us-passport",
"specCodeName": "US Passport",
"alterationAllowed": false,
"photoSize": "2 x 2 in",
"photoPixel": "600 x 600 px",
"backgroundColor": "#FFFFFF"
},
"checks": [
{
"id": "face_detected",
"name": "Face detected",
"status": "pass",
"measured": "1 face",
"expected": "1 face",
"message": "One face was found."
},
{
"id": "head_size_position",
"name": "Head size and position",
"status": "fail",
"measured": "Head height 42% of the frame",
"expected": "Head height about 50% to 69% of the frame (1 to 1 3/8 in)",
"message": "The head is too small. Move closer, or step the camera back in and retake."
},
{
"id": "background",
"name": "Background",
"status": "warn",
"measured": "Off-white with a shadow behind the head",
"expected": "Plain white or off-white, uniform, no shadow",
"message": "The background is uneven. Retake against a plain wall with the light in front of the subject."
},
{
"id": "expression",
"name": "Expression",
"status": "pass",
"measured": null,
"expected": "Neutral, mouth closed",
"message": "The mouth is closed and the expression is neutral."
}
],
"fixSuggestion": null,
"retakeTips": [
"Move closer so the head fills about half to two-thirds of the frame.",
"Stand in front of a plain white or off-white wall, with the light on the face and no shadow behind the head.",
"Do not replace the background or edit the photo. US passport photos must be unaltered."
]
}A real response includes every rule that ran. The list above is shortened.
Specification that allows a correction
When alterationAllowed is true and every failure can be corrected, fixable is true. Badge specifications are account-specific. The YOUR_BADGE_SPEC code below is the same placeholder the badge photo page uses. Branch on the booleans, not on this sample code.
json
{
"pass": false,
"score": 71,
"fixable": true,
"language": "en",
"spec": {
"specCode": "YOUR_BADGE_SPEC",
"specCodeName": "Employee badge",
"alterationAllowed": true
},
"checks": [
{
"id": "expression",
"name": "Expression",
"status": "fail",
"measured": null,
"expected": "Neutral, mouth closed",
"message": "The mouth is open. A correction is allowed for this specification."
},
{
"id": "lighting_shadows",
"name": "Lighting and shadows",
"status": "fail",
"measured": "Strong light from the left",
"expected": "Even light on the face",
"message": "One side of the face is much brighter than the other."
}
],
"fixSuggestion": {
"summary": "Correct the expression and the lighting with the Fix Passport Photo API, then check the portrait again.",
"steps": [
{
"endpoint": "POST /v2/aiEdit",
"reason": "Expression and lighting can be corrected without a new capture on this specification."
}
]
},
"retakeTips": [
"If you would rather retake, ask for a closed mouth and a light source in front of the face."
]
}If the only failures are size or background, and the specification allows that processing, the step is POST /v2/makeIdPhoto with the same specCode. Recheck the file it returns. Do not send a US passport, UK passport, or DV lottery photo down that path: those responses keep fixable false.
After POST /v2/aiEdit, call POST /v2/checkPhoto on the edited image before you treat it as ready. The fix endpoint does not select a document size and does not guarantee acceptance. See the Fix Passport Photo API.
Code examples
curl
bash
curl --request POST \
--url https://api-us.idphotoapp.com/v2/checkPhoto \
--header 'Content-Type: application/json' \
--data '{
"apiKey": "your-api-key",
"apiSecret": "your-api-secret",
"imageBase64": "your-base64-encoded-image",
"specCode": "uk-passport",
"language": "en"
}'Use https://api-eu.idphotoapp.com when the account is configured for the EU region.
Node.js
Run this on the server. Do not ship the secret to a browser.
javascript
import { readFile } from "node:fs/promises";
const image = await readFile("portrait.jpg");
const response = await fetch("https://api-us.idphotoapp.com/v2/checkPhoto", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
apiKey: process.env.IDPHOTO_API_KEY,
apiSecret: process.env.IDPHOTO_API_SECRET,
imageBase64: image.toString("base64"),
specCode: "us-passport",
language: "en",
}),
signal: AbortSignal.timeout(60_000),
});
if (!response.ok) {
throw new Error(`Check failed with HTTP ${response.status}: ${await response.text()}`);
}
const result = await response.json();
if (result.pass) {
console.log("No failing rule. This is not an acceptance decision.");
} else if (result.fixable && result.spec.alterationAllowed) {
console.log(result.fixSuggestion.summary);
} else {
console.log(result.retakeTips.join("\n"));
}Python
python
import base64
import os
import requests
with open("portrait.jpg", "rb") as image_file:
image_base64 = base64.b64encode(image_file.read()).decode("ascii")
response = requests.post(
"https://api-us.idphotoapp.com/v2/checkPhoto",
json={
"apiKey": os.environ["IDPHOTO_API_KEY"],
"apiSecret": os.environ["IDPHOTO_API_SECRET"],
"imageBase64": image_base64,
"specCode": "us-dvlottery",
"language": "en",
},
timeout=60,
)
response.raise_for_status()
result = response.json()
# DV lottery photos are not auto-fixed. alterationAllowed is false.
if not result["pass"]:
for tip in result["retakeTips"]:
print(tip)More Python samples are in Sample Python Code.
Error codes
These are transport and input errors. A photo that fails a rule still returns HTTP 200 and pass: false.
The error body is JSON:
json
{
"code": "INVALID_SPEC_CODE",
"message": "No specification named us-passport-photo was found. Query POST /v2/listIdPhotoSpecCode."
}code | HTTP | When it is returned |
|---|---|---|
INVALID_CREDENTIALS | 401 | The key or secret is missing or not valid. |
FORBIDDEN | 403 | The endpoint is not enabled for this key. |
MALFORMED_REQUEST | 400 | The JSON could not be read, or a required field other than the image is missing. |
MISSING_IMAGE | 400 | No imageBase64, imageUrl, or file was sent. |
MULTIPLE_IMAGE_SOURCES | 400 | More than one image source was sent. |
INVALID_IMAGE | 400 | The bytes are not a readable JPEG or PNG. |
IMAGE_TOO_LARGE | 413 | The file is larger than 10 MB. |
INVALID_IMAGE_URL | 400 | imageUrl is not an HTTPS URL, or it points at a private address. |
IMAGE_FETCH_FAILED | 422 | The URL could not be fetched or was not a JPEG or PNG. |
INVALID_SPEC_CODE | 400 | specCode is not on this account. Query the specification list. |
PROCESSING_FAILED | 500 | The check could not be completed. Safe to retry once with the same image. |
Distinguish these from a successful body whose checks contain fail. Map message for operators. Map checks[].message and retakeTips for the person in front of the camera.
Related
- Photo compliance check
- Fix Passport Photo API (
POST /v2/aiEdit) - Passport Photo API (
POST /v2/makeIdPhoto) - Spec Code
- Issue Codes
