Integrations
PHP
Server-side steps in PHP.
Prerequisites
- PHP with the
opensslandcurlextensions. - The secret key of the scenario and a permanent API token, read from environment variables. Never put them in browser code or in a repository.
- The API address provided with your access.
The call sequence
- Your server encrypts the raw client key with the secret key of the scenario.
- Your page opens the widget with the scenario identifier and the encrypted client key.
- The user completes the steps in the widget.
- Your server learns of the result from the
SESSION_COMPLETEwebhook, or reads session status. - Your server decides on the customer from the server-side status.
Encrypt the client key
The secret key of the scenario never leaves your server. See working with clientKey for the algorithm.
<?php
function encryptClientKey(string $clientKeyRaw, string $secret): string
{
// First 32 characters of the SHA-256 hash of the secret, written as hex.
$key = substr(hash('sha256', $secret), 0, 32);
$iv = random_bytes(16);
$encrypted = openssl_encrypt($clientKeyRaw, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
if ($encrypted === false) {
throw new RuntimeException('client key encryption failed');
}
return base64_encode($iv . $encrypted); // the clientKey for the widget
}
header('Content-Type: application/json');
$clientKeyRaw = (string) $currentUserId; // your own identifier, at most 36 characters
echo json_encode(['clientKey' => encryptClientKey($clientKeyRaw, getenv('SCENARIO_SECRET_KEY'))]);
Store the raw value with your user or order, so that you can match the result later.
Create a session
<?php
function apiPost(string $path, array $body): array
{
$ch = curl_init(getenv('API_BASE_URL') . $path);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($body),
CURLOPT_RETURNTRANSFER => true,
]);
$reply = curl_exec($ch);
curl_close($ch);
return json_decode($reply, true) ?? [];
}
$session = apiPost('/kyc/session/create', [
'token' => getenv('API_TOKEN'), // permanent API token
'schemaId' => getenv('SCENARIO_ID'), // scenario identifier
]);
if (!isset($session['sessionId'])) {
// A failure arrives as a body with status "error" or "failed".
throw new RuntimeException('session was not created: ' . ($session['status'] ?? 'unknown'));
}
// $session['status'] is the session status, "idle"
Read the result with apiPost('/kyc/session/status', ['token' => ..., 'sessionId' => ...]) and branch on status, never on message text. See response format and errors and session statuses.
Troubleshooting
| Symptom | What to check |
|---|---|
| The widget does not open | The domain is in the allowed domains, the page is on HTTPS, and the widget is not inside a cross-origin iframe. See installation. |
| The widget reports that decryption failed | The client key was not encrypted, or a different secret key was used, or the string was cut. See working with clientKey. |
| A call returns success but the body has an error | Branch on the status field of the body. See response format and errors. |
| The result never reaches your server | Check the callback URL in the scenario. See webhooks. |