> For the complete documentation index, see [llms.txt](https://docs.facephi.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facephi.com/docs.facephi-en/sdks/backend-sdk/iad/technical_documentation/technical_specifications.md).

# Technical specifications

## Minimum requirements

| Component | Requirement                   |
| --------- | ----------------------------- |
| OS        | Linux x86\_64 (Ubuntu 20.04+) |
| CPU       | 4 cores                       |
| Memory    | 4 GB RAM                      |
| Disk      | 1 GB of free space            |

## Recommended for production

| Component | Recommendation         |
| --------- | ---------------------- |
| OS        | Ubuntu 24.04 LTS       |
| CPU       | 8+ cores               |
| Memory    | 8 GB+ RAM              |
| Network   | Low-latency connection |
| Storage   | SSD for logs           |

## Network requirements

### Outbound connectivity

The service must be able to reach:

* Facephi license servers (for license validation)

### License server access

**Required IPs and ports:**

| IP           | Port | Protocol |
| ------------ | ---- | -------- |
| 52.223.22.71 | 443  | TCP/IP   |
| 35.71.188.31 | 443  | TCP/IP   |
| 75.2.113.112 | 443  | TCP/IP   |
| 99.83.149.57 | 443  | TCP/IP   |

**Required URLs:**

* `https://api.cryptlex.com:443`
* `https://api.eu.cryptlex.com:443`

Configure firewall rules to allow outbound HTTPS traffic to these endpoints.

## Deployment architecture

IAD Service operates as a stateless Rest API that evaluates capture payloads and returns a public Facephi contract:

```
Client → IAD Service (Port 6982)
```

* Multiple service instances can run behind a load balancer
* Each instance maintains the internal resources necessary for capture processing
* The service does not store session state

## Public API compatibility

{% hint style="danger" %}
**Breaking change notice (2.0.0)** The public Rest API exposed by version 2.0.0 breaks compatibility with the 1.x.x series. This affects the communication contract, not just the documentation. Integrations must migrate the Endpoint routes, the multipart field names, and the parsing rules for correct responses.
{% endhint %}

| Integration area        | 1.x.x                       | 2.0.0                           |
| ----------------------- | --------------------------- | ------------------------------- |
| Liveness Endpoint       | `/api/v1/iad/check-capture` | `/api/v1/iad/liveness/evaluate` |
| Extraction Endpoint     | `/api/v1/iad/extract-image` | `/api/v1/iad/extract`           |
| Multipart request field | `file`                      | `capture`                       |
| Valid Liveness payload  | Inherited private fields    | Facephi public fields           |

## Experimental replay attack mitigation

The service can apply a freshness window to incoming capture payloads. This experimental protection is disabled by default.

* Enable it with `FACEPHI_IAD_REPLAY_ATTACK_CHECKER_ENABLED=true`
* Adjust the freshness window with `FACEPHI_IAD_REPLAY_ATTACK_TOLERANCE_TIME=<seconds>`
* Default freshness window: `300` seconds
* It applies to capture processing endpoints such as `POST /api/v1/iad/liveness/evaluate` and `POST /api/v1/iad/extract`
* When the freshness window is exceeded, the public API returns HTTP `400` with `message` equal to `Replay attack detected`

This functionality is configured at startup using environment variables. It is not part of `config.json` nor exposed through `GET|POST /api/v1/iad/config`.

## JWT authentication

JWT authentication can be enabled at startup via `config.json` or via environment variables `FACEPHI_IAD_REST_AUTH_*`.

* Supported startup keys: `auth_enabled`, `auth_jwt_secret`, `auth_accept_authorization_header`, `auth_accept_api_key_header`, `auth_api_key_header_name`
* `GET /api/v1/iad/config` omits those keys from the public configuration view
* `POST /api/v1/iad/config` rejects those keys and cannot be used to rotate JWT authentication configuration at runtime

## Performance characteristics

| Metric                 | Typical value                                             |
| ---------------------- | --------------------------------------------------------- |
| Latency                | < 100ms                                                   |
| Throughput             | Depends on service sizing and capture processing capacity |
| Concurrent connections | Limited by `number_of_threads` and `engine_pool_size`     |
| Maximum request size   | Configurable via `client_max_body_size`                   |

## Security considerations

* Deploy behind a reverse proxy or an API gateway
* Enable SSL/TLS for all communications
* Prefer injecting `auth_jwt_secret` via environment variables or a secrets manager instead of including it in files
* Protect the license file with the appropriate permissions (chmod 644)
* Use firewall rules to restrict incoming connections

### Facephi-normalized error messages

For `POST /api/v1/iad/liveness/evaluate`, capture validation failures are normalized to public values of `message`, including:

* `NoneBecauseFaceTooClose`
* `NoneBecauseFaceNotFound`
* `NoneBecauseFaceCropped`
* `NoneBecauseFaceOccluded`
* `NoneBecauseTooManyFaces`
* `NoneBecauseAngleTooLarge`
* `NoneBecauseFaceTooSmall`
* `NoneBecauseFaceTooCloseToBorder`
* `NoneBecauseEyesClosed`
* `NoneBecauseImageDataError`
* `NoneBecauseLicenseError`
* `Replay attack detected`
* `ErrorProcessing`

For `POST /api/v1/iad/extract`, payload parsing and decryption failures are returned as `NoneBecauseImageDataError`; expired captures rejected by replay protection return `Replay attack detected`; unclassified extraction failures are returned as `ErrorFacialImage`.

Successful liveness responses are mapped to the public fields `diagnostic`, `reason`, `probability`, `score`, `faceProbability` optional, `sdkDuration` and `queueDuration`. The inherited private fields and the engine's raw payloads are not exposed.

The possible values for `reason` in `POST /api/v1/iad/liveness/evaluate` are:

* `None`
* `Unknown`
* `UntrustedEnvironment`
* `SuspiciousActivity`
* `UntrustedDevice`
* `SdkIntegrityViolation`
* `UntrustedCorruptedPayload`
* `UntrustedContent`
* `UntrustedContentLowConfidence`

The meaning of each public value of `reason` is:

| `reason`                        | Meaning                                                                                                                                              |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `None`                          | The capture was accepted as `Live` and no rejection reason applies.                                                                                  |
| `Unknown`                       | The service could not map the response to a documented public rejection reason.                                                                      |
| `UntrustedEnvironment`          | The capture was rejected because the runtime environment is not considered trusted.                                                                  |
| `SuspiciousActivity`            | The capture was rejected because the device showed activity patterns associated with an attack.                                                      |
| `UntrustedDevice`               | The capture was rejected because the device could not be trusted to be the one it claims to be.                                                      |
| `SdkIntegrityViolation`         | The capture was rejected because the capture SDK or its libraries appear to have been altered.                                                       |
| `UntrustedCorruptedPayload`     | The capture was rejected because the payload appears to be corrupted or tampered with.                                                               |
| `UntrustedContent`              | The capture was rejected because an injection attack was detected.                                                                                   |
| `UntrustedContentLowConfidence` | The capture was rejected because the service detected signs of an injection attack with lower confidence; it should still be treated as a rejection. |
