Continue only if this screening level is sufficient for your business policy.
Build human, document and identity verification from one VettiGuard platform.
Use https://api.vettiguard.com/v1 for new integrations. Keep private credentials and final trust decisions on your backend, then choose the smallest verification surface that satisfies your workflow.
Start with the verification contract that matches the decision you need to make.
Document screening and identity verification are separate surfaces. You can use them independently or compose them into a governed identity journey.
Browser challenge plus private server verification.
/challenge · /siteverify
VettiGuard NativeDocument verificationOCR, MRZ, barcode, capture quality and native screening.
POST /documents/verify
StatefulIdentity verificationDocument evidence plus trusted face/liveness orchestration.
/identity/verification/*
HostedHosted identityServer-created, device-adaptive VettiGuard capture.
/identity/hosted/*
AsyncIdentity webhooksSigned lifecycle events with idempotent delivery.
HMAC-SHA-256
No billing · syntheticDeveloper simulatorExercise document and identity outcomes without sending evidence to production.
verify · recapture · review · reject · 503
OperationsErrors & retriesHandle review, recapture, rate limits and service outages safely.
400 · 401 · 403 · 409 · 429 · 503
Traffic controlRate Limiting as a ServiceApply token buckets, fixed quotas and adaptive token cost before protected operations execute.
/developers/rate-limiting
AuthenticationPasskeys as a ServiceAdd phishing-resistant WebAuthn registration, discoverable sign-in, revocation, and action-bound evidence.
/api/v1/passkeys/*
Selective disclosureDigital credentialsIssue holder-bound identity credentials and reveal only the claims a verifier needs.
/api/v1/credentials/*
Private credentials stay on trusted servers.
Use scoped API credentials where available. Legacy secrets remain accepted only where the endpoint contract documents compatibility. Never embed private credentials, direct identity-session capabilities, or native-service bearer tokens in browser/mobile bundles.
identity.document.verifyidentity.verifyX-VettiGuard-Identity-Session-TokenX-VettiGuard-Hosted-TokenRender the browser widget with a public site key.
The browser receives only the public integration identity. Your backend validates the response token before the protected action runs.
<script src="https://vettiguard.com/assets/captcha.js?v=1786480772" defer></script>
<div class="vettiguard-captcha"
data-sitekey="YOUR_SITE_KEY"
data-action="account-registration"></div>Validate the human-verification response before the protected action.
Require success and validate the expected action, hostname and applicable score/policy contract. Transport errors and unavailable required verification must not become a bypass.
$result = $verifier->verify(
$_POST['vettiguard-response'] ?? '',
$_SERVER['REMOTE_ADDR'] ?? null,
'account-registration'
);
if (!$result->isSuccess()
|| $result->action() !== 'account-registration'
|| $result->hostname() !== 'example.com') {
http_response_code(422);
exit('Verification failed.');
}
// Run the protected action only here.Screen identity documents without starting a full identity session.
POST /v1/documents/verify is the one-shot server-to-server surface. It can inspect front/back evidence, extract machine-readable fields, report capture quality, and return a normalized risk decision. It does not imply government or issuer database confirmation.
Build a supported-document request
Use the capability endpoint before presenting document options in your application.
https://api.vettiguard.com/v1/documents/supportedCountry profiles describe native structural/capture capabilities. They are not issuer certification.
- document_authenticity
native-screening-signals- authoritative_source
not_performedunless a separately governed connector is configured- Client decision
- Never infer “government verified” from native screening.
Credential compatibility: the example below uses the legacy secret request field because the existing one-shot document contract retains it for backward compatibility. Use a scoped server credential where your workspace/API contract enables it.
FRONT_BASE64="$(base64 < id-front.jpg | tr -d '\r\n')"
BACK_BASE64="$(base64 < id-back.jpg | tr -d '\r\n')"
curl -X POST https://api.vettiguard.com/v1/documents/verify \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "{\
\"secret\": \"YOUR_LEGACY_SERVER_SECRET\",\
\"country\": \"AUS\",\
\"document_type\": \"drivers_license\",\
\"front_image\": \"$FRONT_BASE64\",\
\"back_image\": \"$BACK_BASE64\",\
\"require_portrait\": false\
}"$payload = [
'secret' => getenv('VETTIGUARD_SERVER_SECRET'),
'country' => 'AUS',
'document_type' => 'drivers_license',
'front_image' => base64_encode(file_get_contents('/secure/id-front.jpg')),
'back_image' => base64_encode(file_get_contents('/secure/id-back.jpg')),
'require_portrait' => false,
];
$ch = curl_init('https://api.vettiguard.com/v1/documents/verify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Accept: application/json', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES),
]);
$response = json_decode((string) curl_exec($ch), true, 64, JSON_THROW_ON_ERROR);import { readFile } from 'node:fs/promises';
const front = await readFile('/secure/id-front.jpg');
const back = await readFile('/secure/id-back.jpg');
const response = await fetch('https://api.vettiguard.com/v1/documents/verify', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: process.env.VETTIGUARD_SERVER_SECRET,
country: 'AUS',
document_type: 'drivers_license',
front_image: front.toString('base64'),
back_image: back.toString('base64'),
require_portrait: false
})
});
const result = await response.json();{
"success": true,
"verification": {
"provider": "VettiGuard Native",
"checks": {
"image_quality": { "status": "passed" },
"mrz": { "status": "valid" },
"document_authenticity": { "status": "screening_passed" },
"authoritative_source": { "status": "not_performed" }
},
"risk": {
"level": "low",
"decision": "verify"
},
"assurance_boundary": {
"document_authenticity": "native-screening-signals",
"authoritative_source": "not-performed"
}
}
}
Do not silently convert an ambiguous or unavailable check into approval.
Ask the user to retake the document using the returned capture guidance.
Respect final policy outcomes and retain only governed evidence.
Use a stateful session when document evidence must become an identity decision.
Direct sessions support document_only, standard, and high assurance. Standard/high require trusted VettiGuard facial comparison and liveness; browser/mobile “matched” booleans are never authoritative.
POST /identity/verification/sessionPOST /{id}/documentPOST /{id}/facePOST /{id}/completeGET /{id}/resultPOST https://api.vettiguard.com/v1/identity/verification/session
Accept: application/json
Content-Type: application/json
Authorization: Bearer YOUR_SCOPED_SERVER_CREDENTIAL
{
"subject_id": "customer-4821",
"action": "customer-onboarding",
"assurance_level": "high",
"country": "AUS",
"document_type": "drivers_license",
"consent_accepted": true,
"consent_reference": "consent-event-7d1a"
}POST https://api.vettiguard.com/v1/identity/verification/{session_id}/document
Authorization: Bearer YOUR_SCOPED_SERVER_CREDENTIAL
X-VettiGuard-Identity-Session-Token: vg_idv_...
Content-Type: application/json
{
"front_image": "BASE64_JPEG_PNG_OR_WEBP",
"back_image": "OPTIONAL_BASE64_REVERSE_SIDE",
"country": "AUS",
"document_type": "drivers_license"
}GET https://api.vettiguard.com/v1/identity/verification/{session_id}/result
Authorization: Bearer YOUR_SCOPED_SERVER_CREDENTIAL
X-VettiGuard-Identity-Session-Token: vg_idv_...
Accept: application/jsonCreate the browser journey from your backend and let VettiGuard handle capture UX.
The create call is server-authenticated and requires explicit consent plus a non-empty consent reference. The browser receives a separate vgh_ hosted capability, not the underlying direct-session token.
Hosted journey rules
- Hosted capability is delivered in the URL fragment
- Fragment is removed immediately by the hosted client
- Continuation uses
X-VettiGuard-Hosted-Token - Client-supplied match/liveness/score fields are rejected
- Standard/high assurance remains a backend decision
POST https://api.vettiguard.com/v1/identity/hosted/session
Authorization: Bearer YOUR_SCOPED_SERVER_CREDENTIAL
Content-Type: application/json
{
"subject_id": "customer-4821",
"action": "customer-onboarding",
"assurance_level": "high",
"consent_accepted": true,
"consent_reference": "consent-event-7d1a",
"country": "AUS",
"document_type": "drivers_license",
"parent_origin": "https://app.example.com",
"return_url": "https://app.example.com/onboarding/complete",
"theme": "system",
"locale": "en-AU"
}Identity verification is a state machine, not a Boolean.
Preserve VettiGuard states so recoverable captures can be retried and review-required cases remain pending instead of being incorrectly approved or permanently rejected.
Verified
The captured policy and required checks completed successfully.
Recapture required
Recoverable capture quality issue; request a fresh document capture.
Manual review
Keep the protected action pending while an authorised reviewer resolves the case.
Rejected
Respect a final policy rejection and do not retry indefinitely.
Consume signed lifecycle events asynchronously and idempotently.
Verify HMAC-SHA-256 using the raw request body before JSON parsing, enforce a bounded timestamp tolerance, and deduplicate deliveries before running your business action.
identity.verification.verified identity.verification.rejected identity.verification.review_required identity.verification.review_resolved identity.verification.recapture_required identity.verification.cancelled
{unix_timestamp}.{raw_request_body}
Compare signatures in constant time and keep webhook secrets only in server-side secret storage.
Exercise document and identity states without touching production.
The simulator is deterministic and browser-local. It makes no VettiGuard API request, creates no billable verification, and never treats synthetic output as an issuer/government confirmation. Optional sample images stay in your browser and are used only for local preview metadata.
{
"simulation": true,
"status": "ready"
}
{
"simulation": true
}
- Choose a flow and scenario, then run the simulation.
Assurance boundary: simulator responses are synthetic. Native document screening is not authoritative-source confirmation, and browser-supplied biometric claims are never a trusted identity decision.
Retry only when the failure class permits it.
Evaluate the HTTP status and the normalized VettiGuard response. Avoid retry storms, do not bypass unavailable required verification, and reuse idempotency/session semantics where documented.
| Status | Meaning | Recommended handling |
|---|---|---|
400 | Invalid or unsupported input/state | Fix the request; do not blindly retry. |
401 | Credential/session capability invalid | Stop and rotate/re-authenticate as appropriate. |
403 | Scope/workspace/policy restriction | Do not retry until authorization/configuration changes. |
409 | Concurrent session state change | Reload the session/result before deciding whether to retry. |
429 | Rate limit or quota | Honor bounded backoff and quota policy. |
503 | Required verification service unavailable | Fail closed to pending/review; retry with bounded backoff. |
Screening is not issuer confirmation.
document_authenticity represents VettiGuard Native screening signals. Unless a separately governed authoritative connector is configured, authoritative_source remains not performed.
Keep secrets off clients.
Private site secrets, scoped server credentials, identity-session capabilities and native-service bearer tokens belong in backend configuration or secret management.
Use the dedicated API host for new integrations.
https://api.vettiguard.com/v1 is canonical. The legacy https://vettiguard.com/api/v1 base remains a compatibility path for existing integrations.
/challenge/siteverify/documents/verify/documents/supported/identity/verification/*/identity/hosted/*