Menu

Back to Dashboard
Developer Docs

KYC Verification

Add identity and age verification to your platform in minutes. ProntoID handles document scanning, biometric liveness, and compliance — you receive a webhook with the result.

Overview

Introduction

The ProntoID KYC API lets your platform verify users' real-world identities without handling any raw identity data yourself. When your backend calls create-kyc-verification, ProntoID returns a short-lived verification URL. You redirect your user there; ProntoID runs the checks; and then POSTs the structured result to your webhook endpoint.

Each KYC service you create (on the Configure page) gets its own independent pk_live_… / sk_live_… key pair, scoped to a single business name and set of verification requirements. This means you can run separate services for different products, environments, or compliance regions with full isolation.

Overview

How it works

1
Create a KYC service
On the Configure page, set your business name, use case, verification requirements, and webhook URL. ProntoID generates an isolated API key pair.
2
Your backend calls create-kyc-verification
When a user needs to be verified, your server POSTs their internal ID as client_reference to the ProntoID API using your service credentials. You receive back a verification_url.
3
Redirect the user
Send the user to the verification_url. ProntoID guides them through document capture, liveness detection, and age checks — depending on your service configuration.
4
Receive the result via webhook
Once verification completes (pass or fail), ProntoID POSTs a signed JSON payload to your webhook_url. Your server validates and acts on it — never trust the return URL alone.
5
Optionally redirect back to your platform
If you set a return_url, users land back on your site after verification. Use this to show a confirmation screen — but always validate status from the webhook, not the URL.
6
Optionally require a ProntoRelease affidavit
Pass release_required: true, release_type, and an optional community slug when creating the verification. After KYC completes, ProntoID's completion screen redirects the user to sign a legally-binding release affidavit on secure.prontoid.com before returning to your platform.
Setup

Create a service

Each integration starts with a KYC service. Go to Configure KYC Service, fill in your details, and submit. The page will display your API key and secret — copy the secret immediately, it won't be shown again.

A service stores: your business name (shown to users during verification), your requirements (identity, age, liveness, face match), compliance flags (2257, GDPR, payment processor), your webhook URL, an optional return URL, and the set of allowed origins for CORS.

Setup

API credentials

After creating a service you receive two credentials:

KeyFormatUsed in
api_key pk_live_… or pk_test_… X-API-Key header
api_secret sk_live_… or sk_test_… X-API-Secret header
Secret shown once. The api_secret is only returned at creation time. Store it in an environment variable or secrets manager immediately. If lost, rotate via your KYC dashboard.
Never expose credentials client-side. All API calls using your key and secret must be made from your server. Never include them in frontend JavaScript, mobile apps, or version control.
Integration

Create a verification

When a user needs to be verified, your backend makes a POST to the verification endpoint. Pass your user's internal ID as client_reference — this is echoed back in the webhook so you can match results to your users.

POST https://75o3us32d7.execute-api.us-east-1.amazonaws.com/production/create-kyc-verification
PHP — using ProntoIDKYCClient
require_once 'ProntoIDKYCClient.php';

// Credentials from your KYC service
$apiEndpoint = 'https://75o3us32d7.execute-api.us-east-1.amazonaws.com/production/create-kyc-verification';
$apiKey      = 'pk_live_…';
$apiSecret   = 'sk_live_…';

$client = new ProntoIDKYCClient($apiEndpoint, $apiKey, $apiSecret);

// $userId = your internal user identifier
$result = $client->createVerification($userId, [
    'redirect_url'     => 'https://yoursite.com/verified',  // optional
    'state'            => 'order_8821',                      // optional passthrough
    // ProntoRelease — omit if no release form required
    'release_required' => true,                               // require affidavit after KYC
    'release_type'     => 'creator_model',                    // 'creator_model' | 'creator'
    'community'        => 'malibustrings',                    // optional community slug
]);

if ($result) {
    // Redirect the user to start verification
    header('Location: ' . $result['verification_url']);
} else {
    $error = $client->getLastError();
    // Handle error…
}
cURL
curl -X POST \
  https://75o3us32d7.execute-api.us-east-1.amazonaws.com/production/create-kyc-verification \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: pk_live_…' \
  -H 'X-API-Secret: sk_live_…' \
  -d '{
    "client_reference":  "user_abc123",
    "redirect_url":      "https://yoursite.com/verified",
    "state":             "order_8821",
    "release_required":  true,
    "release_type":      "creator_model",
    "community":         "malibustrings"
  }'

Success response 200

JSON
{
  "success":            true,
  "request_id":         "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "verification_token": "vt_…",
  "verification_url":   "https://verify.prontoid.com/start?token=vt_…",
  "expires_at":         1735430400,
  "client_reference":   "user_abc123"
}
Integration

Redirect the user

Send the user to the verification_url returned from the API. The URL is single-use and expires — do not cache it. ProntoID will guide the user through the configured checks (document capture, liveness, age gate) and then redirect to your return_url if one is set.

The return_url only signals that the flow ended — it carries no verification result. Always wait for the webhook before granting access or marking a user as verified.
Integration

Webhook

ProntoID POSTs verification results to the webhook_url you set when creating the service. Your endpoint must respond with HTTP 200; any other status or a timeout triggers a retry.

The webhook is the only authoritative source of truth for verification status. Never rely on query parameters from the return URL.

Example webhook handler — PHP

PHP
// kyc-webhook.php
$payload = json_decode(file_get_contents('php://input'), true);

if ($payload['status'] === 'approved') {
    $userId = $payload['client_reference'];  // your internal user ID
    // Mark user as verified in your database
    markUserVerified($userId);
}

// Always respond 200 to acknowledge receipt
http_response_code(200);
echo json_encode(['received' => true]);
Integration

PHP client library

Drop ProntoIDKYCClient.php into your project. It handles request signing, JSON encoding, cURL transport, and error surfacing. No Composer dependency required.

ProntoIDKYCClient.php
PHP · No dependencies · v1.0
Download
PHP — full usage
require_once 'ProntoIDKYCClient.php';

$client = new ProntoIDKYCClient(
    'https://75o3us32d7.execute-api.us-east-1.amazonaws.com/production/create-kyc-verification',
    $_ENV['PRONTOID_API_KEY'],
    $_ENV['PRONTOID_API_SECRET']
);

$result = $client->createVerification($userId, [
    'redirect_url'     => 'https://yoursite.com/verified',
    'state'            => 'order_8821',
    'metadata'         => ['plan' => 'premium'],
    // ProntoRelease (omit if no release form required)
    'release_required' => true,
    'release_type'     => 'creator_model',  // 'creator_model' | 'creator'
    'community'        => 'malibustrings',  // optional community slug
]);

if ($result) {
    header('Location: ' . $result['verification_url']);
    exit;
}

// Error handling
$error    = $client->getLastError();     // human-readable message
$httpCode = $client->getLastHttpCode(); // raw HTTP status
Store credentials in environment variables or a secrets manager, never hard-coded. Rotate them from your KYC dashboard if compromised.
Reference

Request parameters

ParameterTypeRequiredDescription
client_reference string Required Your internal user ID. Echoed back in the webhook so you can match results.
redirect_url string (URL) Optional Override the return_url set on the service for this specific request.
webhook_url string (URL) Optional Override the service-level webhook URL for this request only.
state string Optional Arbitrary string passed through the flow and included in the webhook payload. Useful for correlating verifications with orders, sessions, etc.
metadata object Optional Key-value pairs attached to the verification record. Not exposed to the end user.
release_required boolean Optional Set to true to require the user to sign a ProntoRelease affidavit after KYC completes. When true, the completion screen replaces the normal "Go to website" button with a "Sign Release Form" CTA that routes to secure.prontoid.com/release-form.php. Defaults to false.
release_type string Optional Required when release_required is true. Controls which affidavit form is presented:

creator_model — the user is both subject and producer (self-posted content, selfie-style). Signs a combined performer + producer release.

creator — the user is a photographer or videographer. Signs a producer-only release including a structured records-keeping address and model warrant.
community string Optional Community slug used to skin the release form and set the post-signing redirect. For example, malibustrings loads the MalibuStrings-branded affidavit and redirects to malibustrings.bentbox.co/dashboard on completion. Omit to use the platform-level default config.
Reference

Response fields

FieldTypeDescription
successbooleantrue when the verification session was created successfully.
request_idstring (UUID)Unique ID for this verification request. Log this for support queries.
verification_tokenstringShort-lived token embedded in verification_url. Single-use.
verification_urlstring (URL)The URL to redirect your user to. Expires at expires_at.
expires_atinteger (Unix)Unix timestamp after which the URL is invalid. Typically 30 minutes from creation.
client_referencestringEcho of the client_reference you submitted.
Reference

Webhook payload

ProntoID sends a POST with Content-Type: application/json to your webhook URL. Respond with HTTP 200 to acknowledge.

JSON — approved
{
  "event":            "verification.completed",
  "request_id":       "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "client_reference": "user_abc123",
  "status":           "approved",  // "approved" | "rejected" | "pending_review"
  "state":            "order_8821",
  "completed_at":     1735430400,
  "checks": {
    "identity_verification": "passed",
    "age_verification":      "passed",  // present if enabled
    "liveness_check":        "passed",  // present if premium+
    "face_match":            "passed"   // present if premium+
  },
  "metadata": { "plan": "premium" }
}
Reference

Service tiers

FeatureBasicPremiumEnterprise
Identity verification
Age verification
Liveness detection Premium Enterprise
Face matching Premium Enterprise
Document authentication Enterprise
Watchlist screening Enterprise
Pricing $0.50 / verification $1.00 / verification + $29/mo Custom — contact sales
Reference

Error codes

HTTPMessageCause & fix
400 Missing required field A required parameter was omitted. Check client_reference, headers.
401 Authentication required Missing or invalid X-API-Key / X-API-Secret headers.
403 Permission denied The credentials do not belong to this service, or the service is inactive.
409 Service ID conflict Duplicate service creation race condition — retry once.
429 Rate limit exceeded Too many requests. Back off and retry with exponential delay.
500 Server error Transient server-side error. Log request_id and contact support if it persists.
ProntoRelease

Overview

ProntoRelease extends the KYC flow with a legally-binding digital affidavit signed by the user immediately after their identity is verified. It is designed for platforms hosting user-generated content — particularly adult or rights-sensitive material — where both identity and authorisation must be established in a single, tamper-evident record.

ProntoRelease handles two distinct legal relationships: a Creator / Model release for users who are both the subject and producer of their content (self-posted material), and a Photographer / Videographer release for users who produce content featuring other performers. Both release types generate a SHA-256-anchored PDF affidavit stored on prontoid-private S3 with AES-256 encryption, retained for seven years.

Where requires_2257 is enabled on the release service config, the affidavit includes the mandatory 18 U.S.C. § 2257 custodian clause, naming Brooks & Keitt Sàrl (Place du Midi 30, 1950 Sion, Switzerland) as the designated custodian of age-verification records.

ProntoRelease is a separate contracted service. Contact info@prontoid.com to enable it for your account and configure community-level settings.
ProntoRelease

Release parameters

The three ProntoRelease parameters are passed alongside the standard create-kyc-verification request body. They are stored on the verification session and read by the ProntoID completion screen to decide whether to show the release form CTA.

ParameterTypeRequiredDescription
release_required boolean Required Must be true to trigger the release flow. When false (default), the normal KYC-only flow runs and the user is sent to return_url as usual.
release_type string Required creator_model — the user is both the subject and the producer of their content (e.g. selfie-style posts). The affidavit combines a performer sworn statement and a producer identification clause.

creator — the user is a photographer or videographer uploading content featuring other performers. The affidavit is producer-only and includes a structured records-keeping address field and a mandatory model records warrant when § 2257 is enabled.
community string Optional A community slug registered in prontoid-release-services. Controls the branding of the affidavit form, the platform and community names shown on the PDF, and the post-signing redirect URL. If omitted, the platform-level default config is used (identified by the _platform sentinel slug).

Example: malibustrings renders the MalibuStrings affidavit and redirects to malibustrings.bentbox.co/dashboard after signing.
The community slug must match a record in your prontoid-release-services table that is linked to the same kyc_service_id as the session. A mismatch returns a 403 from the release form fetch Lambda.
ProntoRelease

Code example

The example below shows a typical BentBox-style integration where the user selects their role (Model or Photographer) on your site before KYC begins. The role maps directly to release_type.

PHP — Creator / Model
// User selected "Verify as Model" on your platform
$result = $client->createVerification($userId, [
    'release_required' => true,
    'release_type'     => 'creator_model',
    'community'        => 'malibustrings',  // optional
]);

// After KYC: user sees "Identity Verified — One More Step"
// with a "Sign Release Form →" button instead of "Go to website".
// Clicking it routes to:
// secure.prontoid.com/release-form.php?access_token=…&community=malibustrings
PHP — Photographer / Videographer
// User selected "Verify as Photographer" on your platform
$result = $client->createVerification($userId, [
    'release_required' => true,
    'release_type'     => 'creator',
    'community'        => 'malibustrings',  // optional
]);

// After KYC: user sees "Sign Photographer Release →" button.
// The release form collects a structured records-keeping address
// and renders the producer-only affidavit with § 2257 model warrant.
PHP — KYC only (no release)
// Standard KYC — no release form (release_required defaults to false)
$result = $client->createVerification($userId, [
    'redirect_url' => 'https://yoursite.com/verified',
    'state'        => 'order_8821',
]);

// After KYC: user is sent to return_url as normal.
ProntoRelease

Post-KYC flow

1
User selects role on your platform
Your UI presents "Verify as Model" or "Verify as Photographer". This maps to release_type: creator_model or release_type: creator in the API call.
2
Your backend creates the verification with release params
Pass release_required: true, release_type, and optionally community. These are stored on the verification session in KycConfig.
3
User completes KYC on verify.prontoid.com
Document capture, liveness detection, and age verification run as normal. The completion screen detects release_required and shows "Sign Release Form →" instead of the normal return button.
4
User reviews and signs the affidavit
On secure.prontoid.com/release-form.php, the form is pre-filled with verified identity data (name, DOB, nationality). The user adds aliases or a records address, types their signature, and submits. A SHA-256-anchored PDF is generated and stored in S3.
5
User is redirected to your platform
After signing, the user is sent to the return_url configured on the release service (community-level or platform-level). A release_token and document_hash are displayed on the success screen as permanent references.
6
Records retained for seven years
Brooks & Keitt Sàrl acts as the designated § 2257 custodian. The signed PDF, verification session, and ID capture are linked by verification_token in prontoid-release-records and retained until the retain_until date.
One verification session can only produce one release record. The submit Lambda checks the verification_token-index GSI before writing — a duplicate submission returns the existing release_token gracefully.