Document Verification — Global Passport
curl --request POST \
--url https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport \
--header 'Content-Type: multipart/form-data' \
--header 'x-access-token: <api-key>' \
--form document_front=@example-file \
--form selfie_image=@example-file \
--form country=RWimport requests
url = "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport"
files = {
"document_front": ("example-file", open("example-file", "rb")),
"selfie_image": ("example-file", open("example-file", "rb"))
}
payload = { "country": "RW" }
headers = {"x-access-token": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document_front', '<string>');
form.append('selfie_image', '<string>');
form.append('country', 'RW');
const options = {method: 'POST', headers: {'x-access-token': '<api-key>'}};
options.body = form;
fetch('https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-access-token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-access-token", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport")
.header("x-access-token", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-access-token"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"valid": true,
"first_name": "<string>",
"last_name": "<string>",
"full_name": "<string>",
"date_of_birth": "<string>",
"gender": "<string>",
"nationality": "<string>",
"address": "<string>",
"id_number": "<string>",
"serial_number": "<string>",
"id_type": "<string>",
"document_type": "<string>",
"document_country": "<string>",
"expiry_date": "<string>",
"issue_date": "<string>",
"is_expired": true,
"photo": "<string>",
"extra_fields": {},
"face_match": {
"attempted": true,
"verified": true,
"decision": "MATCH",
"confidence_percentage": 123,
"compare_mode": "COMPARISON_NO_LIVENESS",
"selfie_image": "<string>",
"reason": "<string>"
}
},
"message": "Document details retrieved successfully"
}{
"status": "failed",
"data": [
"<unknown>"
],
"message": "<string>"
}{
"status": "failed",
"message": "Authentication credentials were not provided."
}Global
Passport
Verify a passport from any country.
POST
/
api
/
onboarding
/
document_verification
/
passport
Document Verification — Global Passport
curl --request POST \
--url https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport \
--header 'Content-Type: multipart/form-data' \
--header 'x-access-token: <api-key>' \
--form document_front=@example-file \
--form selfie_image=@example-file \
--form country=RWimport requests
url = "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport"
files = {
"document_front": ("example-file", open("example-file", "rb")),
"selfie_image": ("example-file", open("example-file", "rb"))
}
payload = { "country": "RW" }
headers = {"x-access-token": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document_front', '<string>');
form.append('selfie_image', '<string>');
form.append('country', 'RW');
const options = {method: 'POST', headers: {'x-access-token': '<api-key>'}};
options.body = form;
fetch('https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-access-token: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-access-token", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport")
.header("x-access-token", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-access-token"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"selfie_image\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nRW\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"valid": true,
"first_name": "<string>",
"last_name": "<string>",
"full_name": "<string>",
"date_of_birth": "<string>",
"gender": "<string>",
"nationality": "<string>",
"address": "<string>",
"id_number": "<string>",
"serial_number": "<string>",
"id_type": "<string>",
"document_type": "<string>",
"document_country": "<string>",
"expiry_date": "<string>",
"issue_date": "<string>",
"is_expired": true,
"photo": "<string>",
"extra_fields": {},
"face_match": {
"attempted": true,
"verified": true,
"decision": "MATCH",
"confidence_percentage": 123,
"compare_mode": "COMPARISON_NO_LIVENESS",
"selfie_image": "<string>",
"reason": "<string>"
}
},
"message": "Document details retrieved successfully"
}{
"status": "failed",
"data": [
"<unknown>"
],
"message": "<string>"
}{
"status": "failed",
"message": "Authentication credentials were not provided."
}Verify a customer’s passport from any country by uploading a photo of the data page. We read the details, confirm which country issued the passport, and compare the face on the passport with a selfie.
Passports from this country can’t be verified:
The photo can’t be read, for example because part of the passport is cut off:
Passport is single-sided. Only
document_front is needed.country is optional. Send it when you know which country issued the passport. Leave it out and we detect the country from the passport itself.Supported countries
You can verify a passport from any country, including Nigeria, Kenya, Ghana, Côte d’Ivoire, Canada, United States, United Kingdom, Australia, Burundi, China, Congo, Ethiopia, Gambia, India, Indonesia, Japan, Rwanda, Sierra Leone, Somalia, South Africa, South Sudan, Tanzania, Togo, Uganda, Zimbabwe and other countries.Endpoint
POST /api/onboarding/document_verification/passport
Request
Headers
| Header | Value | Required |
|---|---|---|
x-access-token | Your API secret key | Yes |
Content-Type | multipart/form-data | Yes |
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
document_front | file | Yes | Photo or scan of the passport data page. JPG, PNG or single-page PDF, max 10MB |
selfie_image | file | Yes | A selfie to compare against the face on the passport. JPG or PNG, max 5MB |
country | string | No | The country that issued the passport, as a two-letter country code, for example RW. Leave it out to have it detected |
A scanned document can be uploaded as a single-page PDF, for example
-F "document_front=@/path/to/scan.pdf".Example
curl -X POST "https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport" \
-H "x-access-token: YOUR_SECRET_KEY" \
-F "document_front=@/path/to/passport.jpg" \
-F "selfie_image=@/path/to/selfie.jpg" \
-F "country=RW"
const formData = new FormData();
formData.append("document_front", fs.createReadStream("/path/to/passport.pdf"));
formData.append("selfie_image", fs.createReadStream("/path/to/selfie.jpg"));
formData.append("country", "RW"); // optional
const response = await fetch(
"https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport",
{
method: "POST",
headers: { "x-access-token": "YOUR_SECRET_KEY" },
body: formData,
}
);
const data = await response.json();
import requests
response = requests.post(
"https://adhere-api.smartcomply.com/api/onboarding/document_verification/passport",
headers={"x-access-token": "YOUR_SECRET_KEY"},
data={"country": "RW"}, # optional
files={
"document_front": open("/path/to/passport.jpg", "rb"),
"selfie_image": open("/path/to/selfie.jpg", "rb"),
},
)
data = response.json()
Response
200 OK
| Field | Type | Description |
|---|---|---|
status | string | "success" on a successful extraction |
data.full_name | string | Extracted full name |
data.first_name | string | Extracted first name |
data.last_name | string | Extracted last name |
data.date_of_birth | string | Date of birth in YYYY-MM-DD format |
data.gender | string | Extracted gender |
data.nationality | string | Extracted nationality |
data.id_number | string | The passport number |
data.document_type | string | "passport" |
data.document_country | string | The country that issued the passport, as a two-letter country code, for example "RW" |
data.expiry_date | string | Passport expiry date |
data.is_expired | boolean | Always false on a 200. An expired passport fails the check (see Expired passports) |
data.photo | string | Base64-encoded face photo extracted from the passport |
data.extra_fields | object | Other fields read from the data page, such as place_of_birth, place_of_issue, issuing_authority, and mrz_line1/mrz_line2 when the machine-readable zone was legible |
data.face_match | object | Result of comparing the face on the passport with selfie_image |
data.face_match.attempted | boolean | Whether a comparison was run |
data.face_match.verified | boolean | null | true or false if the comparison ran; null if it couldn’t run |
data.face_match.decision | string | "MATCH" or "NO_MATCH" |
data.face_match.confidence_percentage | number | Match confidence, 0 to 100 |
data.face_match.compare_mode | string | "COMPARISON_NO_LIVENESS" means the two photos were compared without a liveness check |
data.face_match.selfie_image | string | URL of the uploaded selfie |
message | string | Human-readable result summary |
{
"status": "success",
"data": {
"valid": true,
"first_name": "Nassra Nassor",
"last_name": "Ngarango",
"full_name": "Nassra Nassor Ngarango",
"date_of_birth": "1990-05-20",
"gender": "F",
"nationality": "TANZANIAN",
"id_number": "TAE661142",
"document_type": "passport",
"document_country": "TZ",
"expiry_date": "2033-11-08",
"is_expired": false,
"photo": "/9j/4AAQSkZJRgABAQAAAQABAAD...",
"extra_fields": {
"place_of_birth": "KINONDONI",
"place_of_issue": "PCO, DAR ES SALAAM",
"issuing_authority": "PCO, DAR ES SALAAM",
"mrz_line1": "P<TZANGARANGO<<NASSRA<NASSOR<<<<<<<<<<<<<<<<",
"mrz_line2": "TAE6611429TZA9005204F3311086<<<<<<<<<<<<<<06"
},
"face_match": {
"attempted": true,
"verified": true,
"decision": "MATCH",
"confidence_percentage": 92.4,
"compare_mode": "COMPARISON_NO_LIVENESS",
"selfie_image": "https://.../selfie.jpg"
}
},
"message": "Document details retrieved successfully"
}
Face match:
verified: false with decision: "NO_MATCH" means the comparison ran and the faces didn’t match. verified: null with a reason means the comparison couldn’t run, for example because no face was found in the selfie. A face-match problem never blocks the passport data: the rest of data is still returned.400 Bad Request
The passport wasn’t issued by thecountry you sent:
{
"status": "failed",
"data": {
"error_code": "VERIFICATION_FAILED"
},
"message": "Document Verification - Passport check failed: This document wasn't issued by the country you chose. Please upload a document from that country"
}
{
"status": "failed",
"data": [],
"message": "Passports from this country can't be verified."
}
{
"status": "failed",
"data": {
"error_code": "VERIFICATION_FAILED"
},
"message": "Document Verification - Passport check failed: Part of the document is cut off in the photo. Please retake with all edges and corners fully visible."
}
Expired passports
An expired passport fails the check. The extracted details are still returned indata, with is_expired: true:
{
"status": "failed",
"data": {
"first_name": "Nassra Nassor",
"last_name": "Ngarango",
"id_number": "TAE661142",
"document_type": "passport",
"document_country": "TZ",
"expiry_date": "2021-11-08",
"is_expired": true
},
"message": "Document Verification - Passport check failed: Document has expired."
}
401 Unauthorized
{
"status": "failed",
"message": "Authentication credentials were not provided."
}
For a full list of error codes, see the Error Codes reference.
Authorizations
Your Adhere API secret key
Body
multipart/form-data
Photo or scan of the passport data page. JPG, PNG or single-page PDF, max 10MB.
A selfie to compare against the face on the passport. JPG or PNG, max 5MB.
Optional. The country that issued the passport, as an two-letter country code. Leave it out to have it detected.
Example:
"RW"

