Endpoint to open a KYC/KYB session and obtain flow start URLs.
API para Cajeros y Control de Accesos
Para los cajeros y control de accesos, utiliza la siguiente API:
curl -X POST "https://api.facekyc.com/v1/orderrequest.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"atmId": "ES_ONLINE",
"reference": "order_123"
}'
// JavaScript (fetch)
const res = await fetch("https://api.facekyc.com/v1/orderrequest.php", {
method: "POST",
headers: {
"Authorization": "Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json"
},
body: JSON.stringify({
atmId: "ES_ONLINE",
reference: "order_123"
})
});
const data = await res.json();
console.log("session:", data.session_id, "pwa:", data.pwa_url);
<?php
// PHP with GuzzleHttp
require __DIR__."/vendor/autoload.php";
use GuzzleHttp\Client;
$client = new Client(["base_uri" => "https://api.facekyc.com"]);
try {
$r = $client->post("/v1/orderrequest.php", [
"headers" => ["Authorization" => "Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
"json" => ["atmId" => "ES_ONLINE", "reference" => "order_123"],
"http_errors" => false
]);
$status = $r->getStatusCode();
$body = json_decode((string)$r->getBody(), true);
var_dump($status, $body);
} catch (\Throwable $e) {
echo "Error: ".$e->getMessage();
}
Respuesta de ejemplo
{
"ok": true,
"session_id": "6a6b0d78e6c84e8490b3f1c2f6a1b2cd",
"status": "pending",
"atm_id": "ES_ONLINE",
"atm_url": "https://api.facekyc.com/atm/start_session.php?session=...&atmId=ES_ONLINE",
"pwa_url": "https://api.facekyc.com/pwa/?session=...&atmId=ES_ONLINE",
"service": { "id": 12, "name": "CONTROL DE ACCESOS", "price": 1.0, "cost_units": 1 },
"contract": { "contrato_id": 345, "empresa_id": 78 },
"credits": { "debited": 1, "remaining": 149 },
"reference": "order_123",
"filled_meta": true
}
Body (JSON)
| Field | Type | Req. | Description |
|---|---|---|---|
atmId | string | cond. | Channel/ATM (A-Z0-9_-). If omitted and there is ATM_DEFAULT in your config, it will be used. |
reference | string | optional | Free reference (order_id, user_id, etc.). |
Authentication
Authorization: Bearer <API_KEY>Authorization: ApiKey <API_KEY>X-API-Key: <API_KEY>
API key is alphanumeric (with dashes), length ≥36. Store keys only in backend.
Errors
| HTTP | error | Comment |
|---|---|---|
| 201 | (ok) | Session created, credits debited. |
| 400 | INVALID_BODY | Malformed JSON. |
| 400 | ATM_NOT_PROVIDED | atmId is missing and no ATM_DEFAULT is configured. |
| 401 | UNAUTHORIZED | Missing API key or it is invalid. |
| 402 | INSUFFICIENT_CREDITS | Insufficient balance (includes required/available). |
| 403 | FORBIDDEN | Service/contract suspended. |
| 403 | SERVICE_DISABLED | Service inactive. |
| 404 | SERVICE_NOT_FOUND | Contract service does not exist. |
| 404 | COMPANY_NOT_FOUND | Company not found. |
| 405 | METHOD_NOT_ALLOWED | Must be POST. |
| 500 | SERVER_ERROR | Internal error (informative message). |
| 500 | CONFIG_NOT_FOUND | Could not load config. |
API para KYC
Para KYC, utiliza la siguiente API:
curl -X POST "https://api.facekyc.com/v1/orderkyc.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_123",
"document_type": "DNI",
"document_number": "12345678Z"
}'
Probar con Postman
Puedes probar ambos endpoints con Postman. Crea una petición POST y usa Bearer <API_KEY>:
1) Cajeros / Control de Accesos
- Auth:
Bearer <API_KEY> - Headers:
Content-Type: application/json - Body (JSON):
{"atmId":"ES_ONLINE","reference":"order_123"}
curl -X POST "https://api.facekyc.com/v1/orderrequest.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"atmId": "ES_ONLINE",
"reference": "order_123"
}'
2) KYC
- Auth:
Bearer <API_KEY> - Headers:
Content-Type: application/json - Body (JSON):
{"user_id":"user_123","document_type":"DNI","document_number":"12345678Z"}
curl -X POST "https://api.facekyc.com/v1/orderkyc.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_123",
"document_type": "DNI",
"document_number": "12345678Z"
}'
Probar con Insomnia
En Insomnia, crea una petición POST y usa Auth → Bearer Token con tu clave:
1) Cajeros / Control de Accesos
- Auth:
Bearer <API_KEY>(tab “Auth” → “Bearer Token”) - Headers:
Content-Type: application/json - Body (JSON):
{"atmId":"ES_ONLINE","reference":"order_123"}
curl -X POST "https://api.facekyc.com/v1/orderrequest.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"atmId": "ES_ONLINE",
"reference": "order_123"
}'
2) KYC
- Auth:
Bearer <API_KEY> - Headers:
Content-Type: application/json - Body (JSON):
{"user_id":"user_123","document_type":"DNI","document_number":"12345678Z"}
curl -X POST "https://api.facekyc.com/v1/orderkyc.php" \
-H "Authorization: Bearer fk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_123",
"document_type": "DNI",
"document_number": "12345678Z"
}'
📱 Native Application Integration (iOS/Android)
If you load the KYC form inside a native application via WebView, you must configure inline video playback. Without this configuration, the camera video will open in fullscreen and overlays (frame, buttons, countdown) will disappear.
Express:
allowsInlineMediaPlayback={true}
mediaPlaybackRequiresUserAction={false}
iOS - Swift (WKWebView)
Configure the WKWebViewConfiguration before creating the WebView:
import WebKit // 1. Crear configuración ANTES del WebView let config = WKWebViewConfiguration() config.allowsInlineMediaPlayback = true config.mediaTypesRequiringUserActionForPlayback = [] config.allowsPictureInPictureMediaPlayback = false // 2. Crear WebView con la configuración let webView = WKWebView(frame: .zero, configuration: config) // 3. Cargar la URL del KYC let url = URL(string: "https://api.facekyc.com/pwa/kyc_form.php?session=xxx&atmId=xxx")! webView.load(URLRequest(url: url))
iOS - React Native (WebView)
Use the required props in the WebView component:
import { WebView } from 'react-native-webview';
<WebView
source={{
uri: 'https://api.facekyc.com/pwa/kyc_form.php?session=xxx&atmId=xxx'
}}
allowsInlineMediaPlayback={true}
mediaPlaybackRequiresUserAction={false}
allowsFullscreenVideo={false}
javaScriptEnabled={true}
domStorageEnabled={true}
onPermissionRequest={(request) => {
if (request.resources.includes('camera')) {
request.grant();
}
}}
/>
Android - Kotlin/Java (WebView)
Configure the WebSettings and WebChromeClient:
import android.webkit.WebView
import android.webkit.WebSettings
import android.webkit.WebChromeClient
import android.webkit.PermissionRequest
// Configurar WebSettings
val webView = findViewById<WebView>(R.id.webview)
val webSettings = webView.settings
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
webSettings.mediaPlaybackRequiresUserGesture = false
// Gestionar permisos de cámara
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
request.grant(request.resources)
}
}
// Cargar URL
webView.loadUrl("https://api.facekyc.com/pwa/kyc_form.php?session=xxx&atmId=xxx")
Required Configurations
| Platform | Property | Description |
|---|---|---|
| iOS | allowsInlineMediaPlayback |
Allows video to play inline instead of fullscreen |
| iOS | mediaTypesRequiringUserActionForPlayback |
Empty array allows autoplay without screen interaction |
| iOS | allowsPictureInPictureMediaPlayback |
Disables picture-in-picture to avoid conflicts |
| Android | mediaPlaybackRequiresUserGesture |
False allows camera to start automatically |
| Android | WebChromeClient.onPermissionRequest |
Handles camera and microphone permissions |
Required Permissions
iOS - Info.plist:
<key>NSCameraUsageDescription</key> <string>Necesitamos acceso a la cámara para verificación de identidad KYC</string> <key>NSMicrophoneUsageDescription</key> <string>Necesitamos acceso al micrófono para grabación de vídeo KYC</string>
Android - AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" />
Good practices
- Idempotency: Reuse your reference to avoid duplicates on retries.
- Security: Store the API key only on the backend (never in client apps).
- Backoff: On 402/403/5xx, retry with exponential backoff.