curl --request POST \
--url https://adhere-api.smartcomply.com/api/onboarding/document_verification \
--header 'Content-Type: multipart/form-data' \
--header 'x-access-token: <api-key>' \
--form document_type=passport \
--form country=nigeria \
--form document_front='@example-file' \
--form document_back='@example-file' \
--form selfie_image='@example-file'import requests
url = "https://adhere-api.smartcomply.com/api/onboarding/document_verification"
files = {
"document_front": ("example-file", open("example-file", "rb")),
"document_back": ("example-file", open("example-file", "rb")),
"selfie_image": ("example-file", open("example-file", "rb"))
}
payload = {
"document_type": "passport",
"country": "nigeria"
}
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_type', 'passport');
form.append('country', 'nigeria');
form.append('document_front', '<string>');
form.append('document_back', '<string>');
form.append('selfie_image', '<string>');
const options = {method: 'POST', headers: {'x-access-token': '<api-key>'}};
options.body = form;
fetch('https://adhere-api.smartcomply.com/api/onboarding/document_verification', 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",
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_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--",
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"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--")
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")
.header("x-access-token", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--")
.asString();require 'uri'
require 'net/http'
url = URI("https://adhere-api.smartcomply.com/api/onboarding/document_verification")
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_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--"
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>",
"expiry_date": "<string>",
"issue_date": "<string>",
"is_expired": true,
"photo": "<string>",
"extra_fields": {},
"face_match": {
"attempted": true,
"verified": true,
"confidence_percentage": 123,
"selfie_image": "<string>",
"reason": "<string>"
}
},
"message": "Document details retrieved successfully"
}{
"status": "failed",
"data": [
"<unknown>"
],
"message": "<string>"
}{
"status": "failed",
"message": "Authentication credentials were not provided."
}Passport
Extract identity details from a UK passport using OCR.
curl --request POST \
--url https://adhere-api.smartcomply.com/api/onboarding/document_verification \
--header 'Content-Type: multipart/form-data' \
--header 'x-access-token: <api-key>' \
--form document_type=passport \
--form country=nigeria \
--form document_front='@example-file' \
--form document_back='@example-file' \
--form selfie_image='@example-file'import requests
url = "https://adhere-api.smartcomply.com/api/onboarding/document_verification"
files = {
"document_front": ("example-file", open("example-file", "rb")),
"document_back": ("example-file", open("example-file", "rb")),
"selfie_image": ("example-file", open("example-file", "rb"))
}
payload = {
"document_type": "passport",
"country": "nigeria"
}
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_type', 'passport');
form.append('country', 'nigeria');
form.append('document_front', '<string>');
form.append('document_back', '<string>');
form.append('selfie_image', '<string>');
const options = {method: 'POST', headers: {'x-access-token': '<api-key>'}};
options.body = form;
fetch('https://adhere-api.smartcomply.com/api/onboarding/document_verification', 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",
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_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--",
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"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--")
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")
.header("x-access-token", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--")
.asString();require 'uri'
require 'net/http'
url = URI("https://adhere-api.smartcomply.com/api/onboarding/document_verification")
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_type\"\r\n\r\npassport\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nnigeria\r\n-----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=\"document_back\"; 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--"
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>",
"expiry_date": "<string>",
"issue_date": "<string>",
"is_expired": true,
"photo": "<string>",
"extra_fields": {},
"face_match": {
"attempted": true,
"verified": true,
"confidence_percentage": 123,
"selfie_image": "<string>",
"reason": "<string>"
}
},
"message": "Document details retrieved successfully"
}{
"status": "failed",
"data": [
"<unknown>"
],
"message": "<string>"
}{
"status": "failed",
"message": "Authentication credentials were not provided."
}document_front is needed.selfie_image is required — the face extracted from the document is compared against it. This is a still-image comparison (not liveness).Endpoint
POST /api/onboarding/document_verification
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_type | string | Yes | passport |
country | string | Yes | uk |
document_front | file | Yes | Photo of the passport data page. JPG or PNG, max 5MB |
selfie_image | file | Yes | A selfie to compare against the document’s face photo. JPG or PNG, max 5MB |
Example
curl -X POST "https://adhere-api.smartcomply.com/api/onboarding/document_verification" \
-H "x-access-token: YOUR_SECRET_KEY" \
-F "document_type=passport" \
-F "country=uk" \
-F "document_front=@/path/to/passport.jpg" \
-F "selfie_image=@/path/to/selfie.jpg"
const formData = new FormData();
formData.append("document_type", "passport");
formData.append("country", "uk");
formData.append("document_front", fs.createReadStream("/path/to/passport.jpg"));
formData.append("selfie_image", fs.createReadStream("/path/to/selfie.jpg"));
const response = await fetch(
"https://adhere-api.smartcomply.com/api/onboarding/document_verification",
{
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",
headers={"x-access-token": "YOUR_SECRET_KEY"},
data={"document_type": "passport", "country": "uk"},
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.expiry_date | string | Passport expiry date |
data.is_expired | boolean | Whether expiry_date has already passed |
data.photo | string | Base64-encoded face photo extracted from the document |
data.extra_fields | object | Other fields OCR read from the data page — place_of_birth, issuing_authority, and mrz_line1/mrz_line2 if the machine-readable zone was legible, exactly as printed |
data.face_match | object | Result of comparing the document’s face against selfie_image — see below |
data.face_match.attempted | boolean | Whether a comparison was actually run |
data.face_match.verified | boolean | null | true/false if the comparison ran; null if it couldn’t (see Face Match Notes) |
data.face_match.confidence_percentage | number | Match confidence, 0–100 |
data.face_match.selfie_image | string | URL of the uploaded selfie |
message | string | Human-readable result summary |
{
"status": "success",
"data": {
"valid": true,
"first_name": "JAMES",
"last_name": "SMITH",
"full_name": "SMITH JAMES",
"date_of_birth": "1988-07-22",
"gender": "M",
"nationality": "BRITISH",
"id_number": "533018723",
"document_type": "passport",
"expiry_date": "2029-04-15",
"is_expired": false,
"photo": "/9j/4AAQSkZJRgABAQAAAQABAAD...",
"extra_fields": {
"place_of_birth": "LONDON"
},
"face_match": {
"attempted": true,
"verified": true,
"confidence_percentage": 92.4,
"selfie_image": "https://.../selfie.jpg"
}
},
"message": "Document details retrieved successfully"
}
attempted reflects whether a comparison was actually run and verified comes back null with a reason field explaining why — this is different from verified: false, which means the comparison ran and the faces didn’t match. A face-match problem never blocks the underlying document data — the rest of data is still returned.400 Bad Request
{
"status": "failed",
"data": [],
"message": "ID photo is too blurry — please retake in good lighting with a steady hand"
}
401 Unauthorized
{
"status": "failed",
"message": "Authentication credentials were not provided."
}
Authorizations
Your Adhere API secret key
Body
The kind of document being submitted. Which values are valid depends on country — passport works for every supported country; the rest are country-specific.
national_id, passport, drivers_license, voters_card, kenya_id, cac_certificate, utility_bill "passport"
Country the document was issued in.
nigeria, kenya, ghana, canada, usa, cote d'ivoire "nigeria"
Front of the document. JPG or PNG, max 5MB.
Back of the document. Optional for every type, but recommended for two-sided documents (national_id, kenya_id, drivers_license) — extraction may be less complete without it.
A selfie to compare against the face extracted from the document. JPG or PNG, max 5MB. Required for every document_type except cac_certificate and utility_bill, which never carry a face photo and reject the request with 400 if selfie_image is missing for any other type. Still-image comparison only, not liveness.

