curl --request GET \
--url https://api.rial.io/v1/verifications/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.rial.io/v1/verifications/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.rial.io/v1/verifications/{id}', 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://api.rial.io/v1/verifications/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.rial.io/v1/verifications/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.rial.io/v1/verifications/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rial.io/v1/verifications/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"status": "completed",
"capture_url": "https://verify.rial.io/v/vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"created_at": "2026-09-16T19:06:57.718Z",
"expires_at": "2026-09-16T20:06:57.718Z",
"captures_count": 1,
"verdict": {
"rial": false,
"signals": [
"screen_detected"
]
},
"object_match": {
"status": "match",
"expected_object": "car"
},
"location_match": {
"status": "verified",
"expected_location": "Av. Córdoba 5635, Buenos Aires",
"distance_m": 23
},
"condition": {
"score": 8,
"label": "good",
"aspects": [
{
"name": "paint",
"score": 8,
"reasoning": "Even, no visible damage."
}
]
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}Get a verification
The verification and its results: verdict once analysis finished, plus the checks you asked for.
curl --request GET \
--url https://api.rial.io/v1/verifications/{id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.rial.io/v1/verifications/{id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.rial.io/v1/verifications/{id}', 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://api.rial.io/v1/verifications/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.rial.io/v1/verifications/{id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.rial.io/v1/verifications/{id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rial.io/v1/verifications/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"status": "completed",
"capture_url": "https://verify.rial.io/v/vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"created_at": "2026-09-16T19:06:57.718Z",
"expires_at": "2026-09-16T20:06:57.718Z",
"captures_count": 1,
"verdict": {
"rial": false,
"signals": [
"screen_detected"
]
},
"object_match": {
"status": "match",
"expected_object": "car"
},
"location_match": {
"status": "verified",
"expected_location": "Av. Córdoba 5635, Buenos Aires",
"distance_m": 23
},
"condition": {
"score": 8,
"label": "good",
"aspects": [
{
"name": "paint",
"score": 8,
"reasoning": "Even, no visible damage."
}
]
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}Authorizations
Secret API key, created in the dashboard under Settings → API. Send it as Authorization: Bearer rk_secret_… from your server only. Publishable keys (pk_live_…) are for the native SDKs and reach the capture endpoints alone. An unknown key returns 401.
Path Parameters
ULID with vfy_ prefix.
^vfy_[0-9A-HJKMNP-TV-Z]{26}$"vfy_01HXYZABCDEFGHJKMNPQRSTVWX"
Response
Verification including inlined captures with presigned image URLs.
A verification as your API key sees it. verdict appears once analysis finished; object_match, location_match and condition appear when you asked for them and the check ran. Your metadata is not echoed back: keep the id.
^vfy_[0-9A-HJKMNP-TV-Z]{26}$Lifecycle state. pending → first capture flips to partially_captured → analysis sets the verdict and transitions to completed. Terminal: completed, expired, failed. abandoned is a side-branch off pending/partially_captured, reported by the capture screen via POST /v1/verifications/:token/progress when the end user leaves before finishing — NOT terminal: a later capture resurrects the row to partially_captured like any other.
pending, partially_captured, completed, expired, failed, abandoned x >= 0Verdict of a live capture. Branch on rial; signals says why when it is false, and unavailable when a check could not be completed.
- Option 1
- Option 2
Show child attributes
Show child attributes
Where the photo was taken, from the device. Absent for uploaded files and when the device reported no fix.
Show child attributes
Show child attributes
Whether the photo was taken at expected_location. verified within GPS tolerance; no_match somewhere else; ungeocoded when the address or the fix could not be resolved; rejected when the device reported a mock location.
Show child attributes
Show child attributes
Object-check result. Present when an object check was requested globally or on an image step. With step-only configuration the status is the worst step result and expected_object is omitted. Independent of the fraud verdict.
Show child attributes
Show child attributes
Object-check results keyed by image step. Missing capture verdicts yield inconclusive; otherwise each value is the worst context result for the step, ignoring not_applicable when live evidence exists.
Show child attributes
Show child attributes
Condition assessment. Present only when the verification was created with condition_aspects — the free-form tenant-defined aspect names (any language, any domain). score is the one-decimal average of aspect scores; label buckets it (>=7.5 good, >=5 fair, else poor). Independent of the fraud verdict.
Show child attributes
Show child attributes
Analysis of a video-step clip, sampled at one frame per second and run through the same checks a photo gets. Written asynchronously after capture — poll or use webhooks; absent until the worker has run.
Show child attributes
Show child attributes
An earlier verification of yours whose photo matches this one. method: "phash": the perceptual hashes are within threshold (Hamming distance 0–64; 0 is bit-identical) — a re-upload. method: "embedding": the hashes differ but the photos are the same scene by embedding (cosine) and a geometric check confirmed it (inliers) — a screenshot or a crop. Present only when a match was found. It does not change rial: a legitimate re-submission and a recycled photo look the same — your reviewer decides.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Integrity seal over the verification record including answers. Present only when answers exist and sealing is on (seal !== false). The hash proves the stored answers have not changed — it does NOT claim they are true or sensor-attested; answers_provenance carries that distinction explicitly.
- Option 1
- Option 2
Show child attributes
Show child attributes