curl --request POST \
--url https://api.rial.io/v1/link-templates/{slug}/verifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"identification": "POL-001",
"webhook_url": "https://api.acmeinsurance.com/rial/webhooks",
"metadata": {
"claim_id": "CLM-9912"
}
}
'import requests
url = "https://api.rial.io/v1/link-templates/{slug}/verifications"
payload = {
"identification": "POL-001",
"webhook_url": "https://api.acmeinsurance.com/rial/webhooks",
"metadata": { "claim_id": "CLM-9912" }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
identification: 'POL-001',
webhook_url: 'https://api.acmeinsurance.com/rial/webhooks',
metadata: {claim_id: 'CLM-9912'}
})
};
fetch('https://api.rial.io/v1/link-templates/{slug}/verifications', 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/link-templates/{slug}/verifications",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'identification' => 'POL-001',
'webhook_url' => 'https://api.acmeinsurance.com/rial/webhooks',
'metadata' => [
'claim_id' => 'CLM-9912'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://api.rial.io/v1/link-templates/{slug}/verifications"
payload := strings.NewReader("{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rial.io/v1/link-templates/{slug}/verifications")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rial.io/v1/link-templates/{slug}/verifications")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"status": "pending",
"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": 0
}{
"error": {
"code": "<string>",
"message": "<string>",
"fields": [
{
"path": "<string>",
"message": "<string>"
}
]
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}{
"error": "identification_required"
}{
"error": "storage_unavailable"
}Create a verification from a template
Create one verification from a template and get its link. The body overrides the template for this verification: metadata merges, the rest replace.
curl --request POST \
--url https://api.rial.io/v1/link-templates/{slug}/verifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"identification": "POL-001",
"webhook_url": "https://api.acmeinsurance.com/rial/webhooks",
"metadata": {
"claim_id": "CLM-9912"
}
}
'import requests
url = "https://api.rial.io/v1/link-templates/{slug}/verifications"
payload = {
"identification": "POL-001",
"webhook_url": "https://api.acmeinsurance.com/rial/webhooks",
"metadata": { "claim_id": "CLM-9912" }
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
identification: 'POL-001',
webhook_url: 'https://api.acmeinsurance.com/rial/webhooks',
metadata: {claim_id: 'CLM-9912'}
})
};
fetch('https://api.rial.io/v1/link-templates/{slug}/verifications', 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/link-templates/{slug}/verifications",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'identification' => 'POL-001',
'webhook_url' => 'https://api.acmeinsurance.com/rial/webhooks',
'metadata' => [
'claim_id' => 'CLM-9912'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://api.rial.io/v1/link-templates/{slug}/verifications"
payload := strings.NewReader("{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rial.io/v1/link-templates/{slug}/verifications")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rial.io/v1/link-templates/{slug}/verifications")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"identification\": \"POL-001\",\n \"webhook_url\": \"https://api.acmeinsurance.com/rial/webhooks\",\n \"metadata\": {\n \"claim_id\": \"CLM-9912\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "vfy_01HXYZABCDEFGHJKMNPQRSTVWX",
"status": "pending",
"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": 0
}{
"error": {
"code": "<string>",
"message": "<string>",
"fields": [
{
"path": "<string>",
"message": "<string>"
}
]
}
}{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}{
"error": "identification_required"
}{
"error": "storage_unavailable"
}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
Template slug — lowercase [a-z0-9-].
^[a-z0-9]+(?:-[a-z0-9]+)*$"warehouse-intake"
Body
Body for POST /v1/link-templates/{slug}/verifications. Every field is optional and overrides the template: metadata merges key by key, the rest replace.
The value the template asks the person for (customer number, claim id). With a connected database it also picks the row to compare against.
1 - 120Your own key/value pairs. Merged over the template metadata; same key, body wins.
Show child attributes
Show child attributes
HTTPS URL that receives verification.created and verification.completed.
How long the link stays open. Replaces the template default.
60 <= x <= 86400Email that receives the result. null opts this verification out; absent uses the template, then your account default.
254Brand profile to render instead of the template one.
2 - 40^[a-z0-9]+(?:-[a-z0-9]+)*$Response
Verification minted. capture_url is the link to send to the person.
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