7. Fortlink – Face capture via link

Fortlink is a Payface product that enables remote facial capture through a single link generated on the back end (server-side). You can send this link to the end user via SMS, email, WhatsApp, etc., so they complete the selfie flow on their own device.

With one product, you can:

  • Guarantee face liveness
  • Validate identity (selfie + government ID)
  • Enroll a face in the database
  • Identify a previously enrolled face (1:1)

Environments and URLs

⚠️ All examples below use the Sandbox environment.

  • Sandbox base
    https://api-sandbox.fortface.ai

  • Production base
    https://api.fortface.ai

Fortlink endpoints share the same path in both environments; only the base host changes:

  • Create/query Fortlink
    POST/GET {BASE_URL}/backoffice/v1/fortlink

  • Healthcheck (illustrative)
    GET {BASE_URL}/healthcheck

Examples:

  • Create Fortlink in Sandbox:
    POST https://api-sandbox.fortface.ai/backoffice/v1/fortlink

  • Create Fortlink in Production:
    POST https://api.fortface.ai/backoffice/v1/fortlink


Available actions (action)

When creating a Fortlink, you define the operation using the action field:

ActionDescription
livenessVerifies the captured selfie is from a live person (anti-spoofing).
captureCaptures a selfie and validates the person's identity with their ID number.
enrollStores a photo in the biometric database (gallery) for future use.
identifyPerforms 1:1 validation against a previously enrolled face for that user.

Flow overview

  1. Your back end generates the link by calling the Fortlink creation endpoint, setting:

    • externalUserId (your user identifier, e.g., ID number – example: 12345678900)
    • action (one of the actions above)
    • expirationMinutes (link expiration time)
    • webhook (URL to receive the result)
    • redirectURL (HTTPS URL to return the end user to your app after the flow — optional)
  2. You send the linkUrl to the end user (SMS, email, WhatsApp, etc.).

  3. The user opens the link and completes the face capture flow in Fortlink.

  4. You receive the result in two ways:

    • Via webhook (recommended – asynchronous event)
    • Via polling on the Get-Link endpoint.
  5. When redirectURL is configured, after the final screen the App Web redirects the user to that URL (5-second timer or Continue button). Redirect is navigation/UX only — the result is still delivered via webhook.


Authentication

All Fortlink endpoints require:

  • Header x-api-key: {YOUR_API_KEY}
  • Header accept: application/json
  • Header Content-Type: application/json (when there is a body)

Important: never expose your x-api-key on the front end or in public apps.


Security and mTLS

All requests to the Fortlink API are protected with mTLS (Mutual TLS).

  • You must use a valid client certificate to communicate with the endpoints.
  • The certificate must be generated at:
    https://mtls-tool.fortface.com/

Environments protected by mTLS:

EnvironmentBase URL
Sandboxhttps://api-sandbox.fortface.ai
Productionhttps://api.fortface.ai

After generating the certificate in mtls-tool, configure it in your gateway / HTTP client (e.g., NGINX, API Gateway, HTTP library) so that all calls to these bases (Sandbox and Production) use mTLS.

When your HTTPS client supports it, prefer using cert + key instead of a PFX file. To extract the certificate from a PFX: openssl pkcs12 -in file.pfx -clcerts -nokeys -out certificate.crt -passin pass:PASSWORD. Use the .crt and .key in your client options; in some environments, direct PFX usage can fail (for example: "Unsupported PKCS12 PFX data").


Endpoints

Fortlink currently exposes 3 main endpoints:

  1. Create link (POST /backoffice/v1/fortlink)
  2. Get link (GET /backoffice/v1/fortlink/{id})
  3. Healthcheck (GET /healthcheck)

You can also configure a Webhook to receive the operation result.


Endpoint (Sandbox)

POST https://api-sandbox.fortface.ai/backoffice/v1/fortlink

For Production, use:
POST https://api.fortface.ai/backoffice/v1/fortlink

Headers

accept: application/json
x-api-key: {YOUR_API_KEY}
Content-Type: application/json

Body (example – action identify)

{
"externalUserId": "12345678900",
"action": "identify",
"expirationMinutes": 1440,
"webhook": "https://webhook-test.com/example",
"redirectURL": "https://client.example.com/return",
"externalTransactionId": "example-1234"
}

Body parameters

FieldTypeRequiredDescription
externalUserIdstring✅ YesUnique user identifier in your system (e.g., ID number)
actionstring✅ Yesliveness, capture, enroll, or identify
externalTransactionIdstring⚠️ OptionalTransaction ID in your system for traceability
expirationMinutesinteger⚠️ OptionalLink validity in minutes (integer > 0)
webhookstring⚠️ OptionalURL to receive asynchronous result notifications
redirectURLstring⚠️ OptionalHTTPS URL to redirect the end user back to your app after the Fortlink result screen. Does not append process data to the URL
documentstring⚠️ ConditionalRequired when action is capture; valid ID number

redirectURL validation: optional; must be a valid HTTPS URL (HTTP or malformed URLs return 400). Used for browser navigation only; processing results are still delivered via webhook. When set, redirectURL is also included in the webhook payload fortlink object.

cURL example (Sandbox)

curl --location 'https://api-sandbox.fortface.ai/backoffice/v1/fortlink' \
--cert /path/to/your-certificate.pem \
--key /path/to/your-key.key \
--header 'accept: application/json' \
--header 'x-api-key: {YOUR_API_KEY}' \
--header 'Content-Type: application/json' \
--data '{
"externalUserId": "12345678900",
"action": "identify",
"expirationMinutes": 1440,
"webhook": "https://webhook-test.com/example",
"redirectURL": "https://client.example.com/return",
"externalTransactionId": "example-1234"
}'

Response (example)

{
"id": "019ae9ba-7cd4-73dd-bf39-649c0350c06b",
"linkUrl": "https://api-sandbox.fortface.ai/fortlink/019ae9ba-7cd4-73dd-bf39-649c0350c06b",
"externalUserId": "12345678900",
"action": "identify",
"status": "pending",
"expirationMinutes": 1440,
"webhook": "https://webhook-test.com/example",
"redirectURL": "https://client.example.com/return",
"galleryId": "UUID",
"accountName": "test_gallery",
"createdAt": "2025-12-04T14:18:24.340Z",
"expiresAt": "2025-12-05T14:18:24.340Z",
"externalTransactionId": "example-1234"
}


Use this endpoint to check the status of a Fortlink and access the operation output.

Endpoint (Sandbox)

GET https://api-sandbox.fortface.ai/backoffice/v1/fortlink/\{id\}

For Production, use:
GET https://api.fortface.ai/backoffice/v1/fortlink/\{id\}

Replace {id} with the id returned when creating the link.

Headers

accept: application/json
x-api-key: {YOUR_API_KEY}
Content-Type: application/json

cURL example (Sandbox)

curl --location 'https://api-sandbox.fortface.ai/backoffice/v1/fortlink/019ae9bd-9845-7126-85ee-d49cfcc1f769' \
--cert /path/to/your-certificate.pem \
--key /path/to/your-key.key \
--header 'accept: application/json' \
--header 'x-api-key: {YOUR_API_KEY}' \
--header 'Content-Type: application/json'

Response (example – action enroll approved)

{
"id": "019ae9bd-9845-7126-85ee-d49cfcc1f769",
"externalUserId": "12345678900",
"action": "enroll",
"expirationAt": "2025-12-05T14:21:47.973Z",
"webhook": "https://webhook-test.com/example",
"redirectURL": "https://client.example.com/return",
"externalTransactionId": "example-1234",
"galleryId": "UUID",
"accountName": "test_gallery",
"status": "approved",
"linkUrl": "https://api-sandbox.fortface.ai/fortlink/019ae9bd-9845-7126-85ee-d49cfcc1f769",
"output": {
"photo": {
"liveness": {
"value": true,
"confidence": 100
},
"eyesOpen": {
"left": {
"value": true,
"confidence": 64.7906925257821
},
"right": {
"value": true,
"confidence": 67.04287669451382
}
}
},
"sdk": {
"platform": "web",
"appId": "fortlink-sandbox",
"model": "not identified",
"sdkVersion": "2.4.0",
"soVersion": "18.7",
"so": "iOS",
"browser": "Safari",
"browserVersion": "26.1",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.1 Mobile/15E148 Safari/604.1",
"requestSdkConfig": "true"
},
"imageData": "",
"hash": "75FR5OJA8IogI1z23Ia4hHgmEszTrWprRoFxwI78/KFTrszGJWvKkeLoFz4/gnzwAL14IpXkc7yzUKL+RS29eg==",
"api": {
"env": "sandbox",
"timestamp": 1764858237498,
"version": "v1 - 2.56.1"
}
},
"sessionId": "f74b1c97-bf92-469c-a418-1f192f4da44b",
"sessionIds": [
"e5a8b3dd-365a-44c2-b11d-5a3cdc89a3da",
"f74b1c97-bf92-469c-a418-1f192f4da44b"
],
"createdAt": "2025-12-04T14:21:47.973Z"
}


3. Healthcheck

Endpoint to quickly verify the Fortlink environment status.

Endpoint (Sandbox – example)

GET https://api-sandbox.fortface.ai/healthcheck

Endpoint (Production – example)

GET https://api.fortface.ai/healthcheck

cURL example (Sandbox)

curl --location 'https://api-sandbox.fortface.ai/healthcheck' \
--cert /path/to/your-certificate.pem \
--key /path/to/your-key.key \
--header 'accept: application/json' \
--header 'x-api-key: {YOUR_API_KEY}' \
--header 'Content-Type: application/json'


Webhook

The Webhook is the preferred mechanism to receive the face capture result. When the user completes the flow, Fortlink sends a POST to the URL configured in the webhook field when creating the link.

When redirectURL was provided at link creation, the webhook payload fortlink object also includes that field. This helps correlate the event with the end-user return URL; it does not replace the webhook as the result delivery channel.

Sample payload (Sandbox)

{
"sentAt": "2025-12-04T14:23:58.131Z",
"event": {
"id": "019ae9bf-941d-70e3-9533-9fc95c907226",
"type": "link_approved",
"createdAt": "2025-12-04T14:23:57.981Z"
},
"fortlink": {
"id": "019ae9bd-9845-7126-85ee-d49cfcc1f769",
"linkUrl": "https://api-sandbox.fortface.ai/fortlink/019ae9bd-9845-7126-85ee-d49cfcc1f769",
"externalUserId": "12345678900",
"action": "enroll",
"status": "approved",
"expirationAt": "2025-12-05T14:21:47.973Z",
"webhook": "https://webhook-test.com/example",
"redirectURL": "https://client.example.com/return",
"galleryId": "UUID",
"accountName": "test_gallery",
"createdAt": "2025-12-04T14:21:47.973Z",
"externalTransactionId": "example-1234",
"sessionId": "f74b1c97-bf92-469c-a418-1f192f4da44b",
"output": {
"photo": {
"liveness": {
"value": true,
"confidence": 100
},
"eyesOpen": {
"left": {
"value": true,
"confidence": 64.7906925257821
},
"right": {
"value": true,
"confidence": 67.04287669451382
}
}
},
"sdk": {
"platform": "web",
"appId": "fortlink-sandbox",
"model": "not identified",
"sdkVersion": "2.4.0",
"soVersion": "18.7",
"so": "iOS",
"browser": "Safari",
"browserVersion": "26.1",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.1 Mobile/15E148 Safari/604.1",
"requestSdkConfig": "true"
},
"imageData": "",
"hash": "75FR5OJA8IogI1z23Ia4hHgmEszTrWprRoFxwI78/KFTrszGJWvKkeLoFz4/gnzwAL14IpXkc7yzUKL+RS29eg==",
"api": {
"env": "sandbox",
"timestamp": 1764858237498,
"version": "v1 - 2.56.1"
}
}
}
}


End-user redirect (redirectURL)

When redirectURL is provided at link creation:

  1. The user completes the flow and sees the Fortlink final screen (success, failure, rejection, etc.).
  2. After the final screen, the App Web starts a 5-second timer and automatically redirects to redirectURL.
  3. The user can click Continue to return immediately without waiting for the timer.
  4. The URL is opened exactly as registered — no status, scores, tokens, or other process data in the URL.
  5. If the user closes the browser before redirect, the webhook is still sent normally.

Links created without redirectURL keep the current behavior (no automatic redirect).


Fortlink statuses follow this business logic:

PENDING      = "pending"
EXPIRED = "expired"
APPROVED = "approved"
REJECTED = "rejected"
INCONCLUSIVE = "inconclusive"

Definition of each status

PENDING

"pending"

None of the other statuses have been reached yet. The user has not completed the task or the result is still being processed.

EXPIRED

"expired"

The link expiration time has passed (expirationMinutes / expirationAt). The user can no longer use that Fortlink.

APPROVED

"approved"

Capture approved (Hubface capture 4 or 5) and/or liveness approved in actions enroll, identify, and liveness.

REJECTED

"rejected"

Liveness failed more than 5 times (value = false) in actions enroll, identify, and liveness or capture with status 1 or 2 (Hubface).

INCONCLUSIVE

"inconclusive"

Inconclusive capture result: capture with status 0 or 3 (Hubface).

In summary:

  • APPROVED → clear success according to capture / liveness rules.
  • REJECTED → clear failure (multiple liveness failures or capture 1/2).
  • INCONCLUSIVE → capture does not safely allow approval or rejection (Hubface 0/3).
  • PENDING / EXPIRED → flow states (still in progress or expired).

Summary

Fortlink simplifies remote facial capture integration:

  • You generate a link on the server-side (using /backoffice/v1/fortlink).
  • The user completes the selfie in the web flow.
  • You receive the full result via Webhook or by querying by ID.
  • All API communication is protected by mTLS, with certificates generated at: https://mtls-tool.fortface.com/.

Example values used in this document:

  • externalUserId: "12345678900"
  • galleryId: "UUID"
  • webhook: "https://webhook-test.com/example"
  • redirectURL: "https://client.example.com/return" (optional)
  • externalTransactionId: "example-1234"

Environments:

  • Sandbox (BASE): https://api-sandbox.fortface.ai
  • Production (BASE): https://api.fortface.ai

Main path (both environments):

  • POST/GET {BASE_URL}/backoffice/v1/fortlink

Integrate the 3 main points:

  1. POST /backoffice/v1/fortlink – create the link
  2. GET /backoffice/v1/fortlink/{id} – query (polling)
  3. Webhook – receive results asynchronously

Use the actions (liveness, capture, enroll, identify) according to your business flow.