> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vu-one.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate Facial Antispoofing

> How to prepare the image, build the /inference call, handle the info field, and validate your integration before production.

## The full path

<Steps>
  <Step title="Verify connectivity and credentials">
    ```bash theme={null}
    curl -i -X GET "$BASE_URL/version" -H "Api-Key: $VU_AS_FACE_API_KEY"
    ```

    A `200` confirms the base URL and api-key are correct. A `401` means an invalid key or the wrong environment. Check the status code, not the body: version numbers change and are not part of your contract.
  </Step>

  <Step title="Prepare the image">
    Capture or receive a JPEG, resize it to the recommended dimensions, and encode it as base64 with no prefix.
  </Step>

  <Step title="Call POST /inference">
    A single JSON body with `image`, `info`, and `logAnonymity`.
  </Step>

  <Step title="Apply the decision rule">
    `status === 200 && spoofing === false` approves. Everything else does not.
  </Step>
</Steps>

## Image requirements

| Aspect | Value | What happens otherwise |
| - | - | - |
| Recommended resolution | 640 × 480 (or 480 × 640 portrait) | This is the size the service was calibrated on. |
| Hard minimum | 224 × 224 | Below it: `400` with `Image should be larger than [224, 224]`. |
| Format | JPEG, quality ≥ 95 | Aggressive compression erases the very signals the service looks for. |
| Encoding | base64, no `data:` prefix, no line breaks | The service rejects the payload or fails to decode it. |

<Warning>
  **Between 224 × 224 and 640 × 480 there is no error — but there is less detection.** Several analysis layers need resolution to work. A small image passes validation, gets processed, and returns `200` with fewer layers looking at it. This is the most expensive silent failure in this integration: you will not see it in your logs, you will see it in your fraud numbers.
</Warning>

<Tip>
  If your mobile app already captures at higher resolution, resize on the server before sending. Sending 4,000 × 3,000 pixels does not improve detection; it only multiplies response time and payload size.
</Tip>

### Encoding to base64

<CodeGroup>
  ```powershell Windows theme={null}
  [Convert]::ToBase64String([IO.File]::ReadAllBytes("selfie.jpg")) | Set-Content -NoNewline selfie.b64
  ```

  ```bash Linux theme={null}
  base64 -w 0 selfie.jpg > selfie.b64
  ```

  ```bash macOS theme={null}
  base64 -i selfie.jpg -o selfie.b64
  ```
</CodeGroup>

On Linux, `-w 0` suppresses the line breaks `base64` inserts every 76 characters. Without that flag the string arrives split and the service cannot decode it.

## Request body

```json theme={null}
{
  "info": "onboarding-12345",
  "logAnonymity": true,
  "image": "/9j/4AAQSkZJRgABAQAAAQABAAD...v9Un0ooqDE//2Q=="
}
```

| Field | Type | Description |
| - | - | - |
| `image` | string | The selfie in base64, no prefix. Required. |
| `info` | string | Your business reference. **Must be a string**: sending an object returns `422` with `Input should be a valid string`. |
| `logAnonymity` | boolean | Controls the anonymization level VU applies when logging the transaction. Agree on the value with VU according to your data policy. |

<Tip>
  **Always send a non-empty `info`** with an identifier that lets you reconstruct the case: a case number, an onboarding session id, whatever your business uses. It comes back in the response and is what ties a VU transaction to a user in your system when something needs investigating.
</Tip>

## The `info` field in the response

This is where most integrations break. `info` **is not always the same type**:

| What you send | What comes back in `info` | Where your reference lands |
| - | - | - |
| An `info`, and diagnostics are attached | An **object** | In `info.info` (may be `null`) |
| An `info`, no diagnostics attached | A **string** (echo of what you sent) | In `info` |
| Nothing | **`null`** | Nowhere |

Resolve it in one place and never read `info` directly:

```js theme={null}
function reference(body) {
  const i = body?.info;
  return i == null             ? null
       : typeof i === "string" ? i
       : i.info ?? null;
}
```

<Warning>
  **In Java, type `info` as `Object`, never as `String`.** This is the number-one cause of integration failures: the mapping works through every test — where `info` comes back as a string — and explodes in production the first time a case carries diagnostics and `info` arrives as an object. The same applies to any strict deserializer.
</Warning>

## Timeouts and retries

| Setting | Value | Why |
| - | - | - |
| Timeout | 30 s | Typical analysis takes hundreds of milliseconds, but leave headroom. |
| Retries | Maximum 2, with backoff | More retries do not improve the outcome and multiply load. |
| What to retry | `499`, and `500`s that do **not** mention the image or the payload | Those are transient service failures. |
| What **not** to retry | `400`, `401`, `422`, and any deterministic `500` | The problem is in your request; retrying returns the same error. |

<Warning>
  **Never retry a response with `spoofing: true`.** It is a verdict, not an error. Retrying until you get a different result turns your antifraud control into a false-approval generator.
</Warning>

## Before going to production

An integration is ready when you can answer yes to all of these:

1. The decision is written in the positive: `status === 200 && spoofing === false`.
2. No branch decides on `errorCode`, `values`, `confidence`, or `info`.
3. `info` is read through a single resolver that handles object, string, and `null`.
4. In typed languages, `info` is declared as a dynamic type or `Object`.
5. `imageQuality` and its subfields are read as optional; no key is assumed present.
6. Images are sent at 640 × 480 with JPEG quality ≥ 95.
7. A pre-check discards images smaller than 224 × 224 before spending a call.
8. base64 is generated with no `data:` prefix and no line breaks.
9. The timeout is set to 30 s.
10. Retries are capped at 2 and limited to `499` and non-deterministic `500`s.
11. Every transaction `id` is logged, along with the environment and a timestamp.
12. The api-key lives only in the backend, in a secret manager, not in source.
13. The team knows that `422 No Face Detected` is a capture problem and `422 Bad request` is a code problem.

<Card title="Responses" icon="list-check" href="/en/vucs/antispoofing-face/responses">
  Next: what every response field means and how to read the diagnostics.
</Card>


## Related topics

- [Facial Antispoofing](/en/vucs/antispoofing-face/introduction.md)
- [VU Cloud Services](/en/vucs/introduction.md)
- [Integrate Connection Fingerprint](/en/vucs/connection-fingerprint/integration.md)
- [Identity Link API Changelog](/en/identity-link/changelog.md)
- [VU Technical Documentation](/en/index.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.