FACEKYC API — Session creation

Endpoint to open a KYC/KYB session and obtain flow start URLs.

POST https://api.facekyc.com/v1/orderrequest.php Auth: Bearer / ApiKey / X-API-Key Content-Type: application/json

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
atmIdstringcond. Channel/ATM (A-Z0-9_-). If omitted and there is ATM_DEFAULT in your config, it will be used.
referencestringoptional 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

HTTPerrorComment
201(ok)Session created, credits debited.
400INVALID_BODYMalformed JSON.
400ATM_NOT_PROVIDEDatmId is missing and no ATM_DEFAULT is configured.
401UNAUTHORIZEDMissing API key or it is invalid.
402INSUFFICIENT_CREDITSInsufficient balance (includes required/available).
403FORBIDDENService/contract suspended.
403SERVICE_DISABLEDService inactive.
404SERVICE_NOT_FOUNDContract service does not exist.
404COMPANY_NOT_FOUNDCompany not found.
405METHOD_NOT_ALLOWEDMust be POST.
500SERVER_ERRORInternal error (informative message).
500CONFIG_NOT_FOUNDCould not load config.

API para KYC

POST https://api.facekyc.com/v1/orderkyc.php Auth: Bearer / ApiKey / X-API-Key Content-Type: application/json

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>:

POST https://api.facekyc.com/v1/orderrequest.php (Cajeros / Control) POST https://api.facekyc.com/v1/orderkyc.php (KYC)

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"
      }'

Abrir Postman

Probar con Insomnia

En Insomnia, crea una petición POST y usa Auth → Bearer Token con tu clave:

POST https://api.facekyc.com/v1/orderrequest.php (Cajeros / Control) POST https://api.facekyc.com/v1/orderkyc.php (KYC)

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"
      }'

Abrir Insomnia

📱 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}

⚠️ Important: These configurations must be applied before creating the WebView. If not configured, the user experience will be incorrect on iOS.

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" />
💡 Tip: Test the integration with a physical device, not simulators. iOS simulators don't have a real camera and may behave differently.

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.