Identity Verification
curl --request POST \
--url https://win.oneshotagent.com/v1/tools/identity/startimport requests
url = "https://win.oneshotagent.com/v1/tools/identity/start"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://win.oneshotagent.com/v1/tools/identity/start', 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://win.oneshotagent.com/v1/tools/identity/start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$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://win.oneshotagent.com/v1/tools/identity/start"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://win.oneshotagent.com/v1/tools/identity/start")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/identity/start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyResearch & Enrich
Identity Verification
Ask a person to verify their identity document in a session they complete themselves
POST
/
v1
/
tools
/
identity
/
start
Identity Verification
curl --request POST \
--url https://win.oneshotagent.com/v1/tools/identity/startimport requests
url = "https://win.oneshotagent.com/v1/tools/identity/start"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://win.oneshotagent.com/v1/tools/identity/start', 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://win.oneshotagent.com/v1/tools/identity/start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$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://win.oneshotagent.com/v1/tools/identity/start"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://win.oneshotagent.com/v1/tools/identity/start")
.asString();require 'uri'
require 'net/http'
url = URI("https://win.oneshotagent.com/v1/tools/identity/start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyStatus: Building. Not yet taking sessions: the start answers
service_unavailable until the account behind it is live.Request
| Field | Required | Meaning |
|---|---|---|
full_name | yes | The name as on their document (1 to 200 characters) |
email | no | Deleted when the session ends |
purpose | yes | Shown on the consent page (at most 140 characters) |
idempotency_key | yes, or the Idempotency-Key header | 1 to 255 letters, digits, _ . : -; same key and input, same session |
const session = await agent.route('POST', '/v1/tools/identity/start', {
paid: true,
body: { full_name: 'Jane Doe', purpose: 'Confirm the account holder before a payout' },
idempotencyKey: 'kyc-2026-10-jane-doe',
wait: false, // the 202 is the answer: the person decides only after you hand them the link
});
// Hand session.verification_url to the person.
202 with request_id, receipt_id, status (pending), verification_url and expires_at.
The caller proves its wallet: an access token, or X-Agent-ID with a signed x-agent-proof on every leg (the SDKs do).
Result
PollGET /v1/requests/{request_id}. When the session ends, status is completed and result holds:
| Field | Meaning |
|---|---|
status | approved, declined, resubmission_requested, expired (7 days) or abandoned (declined consent) |
reason | Our words: verified, name_does_not_match_document, document_expired, poor_image_quality, declined_consent and the like |
document_type | passport, id_card, residence_permit, drivers_license, visa or other; null without a document |
issuing_country | Two-letter code; null without a document |
name_matches | true or false against full_name; null without a name |
decided_at | When the decision was made |
resubmission_requested included, ends the session. Only the paying agent reads it.
What is kept
The fields above, as long as the job; the email goes when the session ends. Never: document number, images, date of birth, address, face match score.The consent page
{Organisation or agent name} asks you to verify your identity. Reason given: “{purpose}”. You will photograph an identity document and your face. Our verification provider checks them and deletes the images after {N} days. OneShot keeps only the result: whether you were verified, the document type and country, and the date. It never keeps the images or the document number. [Continue] [Decline]
Errors
service_unavailable (503; any charge returned), invalid_input and invalid_idempotency_key (400), agent_proof_required (401), approval_required (403; retry with X-Approval-Id), action_denied_by_policy (403), request_in_flight (409; retry), idempotency_key_reuse (422).
start_unconfirmed and charge_unrecorded (500): use a new key. Uniquely matched confirmed charges return as credits after 30 minutes, even with unconfirmed sessions. Unmatched or ambiguous charges require review; automatic credits aren’t guaranteed.