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

# Referencia común de FaceAuth

> El objeto FaceAuthSubmission y el formato de respuesta de error que comparten todos los endpoints de la API de FaceAuth, además de los cambios necesarios para pasar del endpoint anterior (/v3/faceauth) a /v3/face-auth.

<Warning>
  **La API de FaceAuth se ha trasladado a `/v3/face-auth`.**

  La estructura de la respuesta, los nombres de los campos y el formato de error difieren del endpoint anterior `/v3/faceauth`. Para migrar una integración existente, empiece por [Migrar desde la API anterior](#migrar-desde-la-api-anterior) en esta misma página.
</Warning>

Esta página reúne las definiciones que comparten varios endpoints. Cada página de endpoint hace referencia a ellas por su nombre y documenta únicamente lo que cambia en ese endpoint.

* [Objeto FaceAuthSubmission](#objeto-faceauthsubmission): lo usan la respuesta de creación de [POST](/es/idcheck/add-on/post-faceauth), los elementos de `items[]` de la [consulta de lista](/es/idcheck/add-on/get-faceauth) y la respuesta de la [consulta individual](/es/idcheck/add-on/get-faceauth_detail).
* [Respuestas de error](#respuestas-de-error): el formato de error común a todos los endpoints.
* [Migrar desde la API anterior](#migrar-desde-la-api-anterior): los cambios necesarios para pasar una integración de `/v3/faceauth` a `/v3/face-auth`.

## Objeto FaceAuthSubmission

Objeto que contiene la información de un envío de FaceAuth: el resultado de autenticación, la política usada para la decisión y las puntuaciones de la decisión.

<Warning>
  **Los campos nunca se omiten en las respuestas.**

  Las políticas que no se aplicaron, los resultados que no se recopilaron y los arreglos que no corresponden se devuelven con `null` en lugar de eliminar la clave. Por lo tanto, el conjunto de claves del cuerpo de la respuesta es **siempre el mismo**, independientemente del tipo de envío o de la configuración del proyecto, y basta con comprobar `value === null`: no hacen falta comprobaciones con `'field' in obj` ni con `undefined`.

  Los campos cuyo tipo incluye `nullable` son los que pueden ser `null`.
</Warning>

### Campos de nivel superior

<ResponseField name="authId" type="string">
  Clave del envío de FaceAuth. Guárdela: la usan las API de [consulta individual](/es/idcheck/add-on/get-faceauth_detail), [descarga de imagen](/es/idcheck/add-on/get-faceauth_image) y [eliminación](/es/idcheck/add-on/delete-faceauth).
</ResponseField>

<ResponseField name="authStatus" type="string">
  Resultado de autenticación. Uno de `approved` o `rejected`.
</ResponseField>

<ResponseField name="createTime" type="string">
  Momento de creación del envío, en formato RFC 3339 UTC `yyyy-MM-dd'T'HH:mm:ss.SSSZ`. (Por ejemplo, `2026-08-11T10:09:14.028Z`)
</ResponseField>

<ResponseField name="submitType" type="string">
  Modo de envío. `form` corresponde a la pantalla de Face Auth URL y `api` a [POST /v3/face-auth](/es/idcheck/add-on/post-faceauth).
</ResponseField>

<ResponseField name="kycSubmissionId" type="string">
  ID del envío KYC usado como referencia de comparación.
</ResponseField>

<ResponseField name="deleteTime" type="nullable · string">
  Momento en que se completó la eliminación, en formato RFC 3339 UTC. Es `null` en los envíos que no se han eliminado.
</ResponseField>

<ResponseField name="policy" type="object">
  Política usada para la decisión. Los seis elementos están siempre presentes. Consulte [Elementos de policy](#elementos-de-policy) más abajo.
</ResponseField>

<ResponseField name="result" type="object">
  Resultados de la decisión. Los seis campos están siempre presentes. Consulte [Campos de result](#campos-de-result) más abajo.
</ResponseField>

<ResponseField name="signals" type="nullable · object">
  Información complementaria recopilada en la pantalla de Face Auth URL. Consulte [Campos de signals](#campos-de-signals) más abajo.
</ResponseField>

<ResponseField name="rejectComment" type="nullable · array">
  Arreglo de cadenas con los motivos de rechazo. Es `null` en los envíos `approved`.
</ResponseField>

<ResponseField name="failCode" type="nullable · array">
  Arreglo de cadenas con los códigos de rechazo. Es `null` en los envíos `approved`.
</ResponseField>

<Note>
  La respuesta de creación de [POST /v3/face-auth](/es/idcheck/add-on/post-faceauth) **no** incluye `policy`. El resto de campos es idéntico.
</Note>

### Elementos de policy

Instantánea de la configuración del proyecto en el momento del procesamiento. Cambiar después la configuración del proyecto no altera los valores de los envíos ya creados.

Los seis elementos (`faceSimilarity`, `occluded`, `faceCover`, `headCover`, `liveness`, `activeLiveness`) tienen los dos campos siguientes.

<ResponseField name="enabled" type="boolean">
  Indica si esta política estaba activada cuando se procesó el envío. Determine si una política se aplicó a partir de este valor, no de `threshold`.
</ResponseField>

<ResponseField name="threshold" type="nullable · number">
  Criterio numérico usado para la decisión. Es `null` cuando `enabled` es `false` o cuando la política no usa un criterio numérico.
</ResponseField>

| Elemento         | Política                                   | Condición de aprobación                                                                                      |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `faceSimilarity` | Similitud facial                           | `result.faceSimilarity` es igual o superior a `threshold`                                                    |
| `occluded`       | Prohibición de cubrir el rostro            | El rostro no está cubierto. No usa criterio numérico, por lo que `threshold` es siempre `null`               |
| `faceCover`      | Equipo de protección facial obligatorio    | Se detecta mascarilla, gafas u otro equipo con una confianza igual o superior a `threshold`                  |
| `headCover`      | Equipo de protección de cabeza obligatorio | Se detecta casco u otro equipo con una confianza igual o superior a `threshold`                              |
| `liveness`       | Passive Liveness                           | `result.livenessScore` es igual o superior a `threshold`                                                     |
| `activeLiveness` | Active Liveness                            | `result.activeLivenessScore` es igual o superior a `threshold`. Solo se ejecuta en envíos `submitType: form` |

<Warning>
  **`occluded` y `faceCover` / `headCover` tienen propósitos opuestos.**

  `occluded` prohíbe cubrir el rostro, mientras que `faceCover` y `headCover` exigen llevar equipo de protección. Los nombres se parecen, pero las condiciones de aprobación son inversas. Estas dos últimas existen para entornos como los industriales, donde el equipo de protección es obligatorio.
</Warning>

<Note>
  **`enabled` es un ajuste del proyecto, no un resultado de ejecución.**

  Una política activada puede no ejecutarse según el modo de envío. Si realmente se ejecutó se determina con el campo correspondiente de `result`: `null` significa que no se ejecutó. Hoy la única diferencia de este tipo aparece en `activeLiveness`. Un envío `submitType: api` devuelve `result.activeLivenessScore` como `null` incluso con `enabled: true`, y es el comportamiento esperado.
</Note>

### Campos de result

El campo de resultado de una política que no se ejecutó es `null`. Por ejemplo, un envío con `policy.liveness.enabled` en `false` tiene `livenessScore` como `null`.

<ResponseField name="faceSimilarity" type="nullable · number">
  Puntuación de similitud facial, entre 0 y 100 inclusive. Puede incluir decimales.
</ResponseField>

<ResponseField name="livenessScore" type="nullable · number">
  Puntuación de Passive Liveness.
</ResponseField>

<ResponseField name="activeLivenessScore" type="nullable · number">
  Puntuación de Active Liveness. Siempre es `null` en los envíos `submitType: api`.
</ResponseField>

<ResponseField name="occluded" type="nullable · object">
  Resultado de la detección de rostro cubierto. `value: true` significa que se consideró cubierto y el envío se rechazó.

  <Expandable title="Properties">
    <ResponseField name="value" type="nullable · boolean">
      Si se detectó o no.
    </ResponseField>

    <ResponseField name="confidence" type="nullable · number">
      Confianza de la decisión, entre 0 y 100 inclusive.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="faceCover" type="nullable · object">
  Resultado de la detección de equipo de protección facial. `value: false` significa que se consideró no llevado y el envío se rechazó. Sus propiedades son las mismas que las de `occluded`.
</ResponseField>

<ResponseField name="headCover" type="nullable · object">
  Resultado de la detección de equipo de protección de cabeza. `value: false` significa que se consideró no llevado y el envío se rechazó. Sus propiedades son las mismas que las de `occluded`.
</ResponseField>

<Note>
  `occluded`, `faceCover` y `headCover` comparten la misma estructura. Cuando la comprobación no se ejecutó, **el objeto completo es `null`**: nunca se devuelve con solo sus propiedades en `null`.
</Note>

### Campos de signals

Información complementaria recopilada en la pantalla de Face Auth URL. Solo los envíos `submitType: form` con valores recopilados contienen datos aquí; en los envíos `submitType: api` y en aquellos sin valores recopilados **el objeto completo es `null`**. Es informativa y no se usa para la decisión de autenticación.

<ResponseField name="startButtonClickTime" type="nullable · string">
  Momento en que el usuario pulsó el botón de inicio, en formato RFC 3339 UTC.
</ResponseField>

<ResponseField name="cameraProcessInfo" type="nullable · array">
  Registro de los tramos de captura de cámara. Cuando no hay registro es `null`, no un arreglo vacío.

  <Expandable title="Properties">
    <ResponseField name="[i].processStartTime" type="nullable · string">
      Momento de inicio del tramo de captura, en formato RFC 3339 UTC.
    </ResponseField>

    <ResponseField name="[i].processEndTime" type="nullable · string">
      Momento de fin del tramo de captura, en formato RFC 3339 UTC.
    </ResponseField>

    <ResponseField name="[i].type" type="nullable · string">
      Tipo de tramo de captura, como `faceAuth-passive`, `faceAuth-active` o `faceAuth-auto-capture`. La lista de valores no es fija y puede ampliarse sin previo aviso, así que ignore los valores que no reconozca.
    </ResponseField>

    <ResponseField name="[i].error" type="nullable · string">
      Error ocurrido en ese tramo, o `null` si no hubo ninguno. El mensaje se recopila en el navegador del usuario y no tiene un formato fijo, así que no lo use para bifurcar la lógica.
    </ResponseField>
  </Expandable>
</ResponseField>

### rejectComment y failCode

`rejectComment` es una explicación legible por personas; `failCode` es el código sobre el que bifurcar.

<Warning>
  **Bifurque con `failCode`, no con `rejectComment`.** El texto de `rejectComment` cambia sin previo aviso y causas distintas comparten a veces el mismo texto. `Please retry with another face image.` lo usan tanto `liveness_fail` como `active_liveness_fail`.
</Warning>

Los dos arreglos **se corresponden índice a índice y tienen siempre la misma longitud.** El motivo de `failCode[0]` es `rejectComment[0]`.

```json result.json theme={null}
{
  "rejectComment": [
    "Protection equipment is not found on Head.",
    "face compare similarity score is lower than threshold"
  ],
  "failCode": ["Head_cover_fail", "face_compare_underscore"]
}
```

Un mismo envío puede incumplir varias políticas a la vez, así que revise todos los valores del arreglo. El orden sigue el de evaluación de las políticas y no es fijo: no dé por supuesto que un código concreto aparece siempre primero.

Para la lista de valores de `failCode`, consulte [POST /v3/face-auth](/es/idcheck/add-on/post-faceauth).

### Notas para el procesamiento de respuestas

* El conjunto de claves de una respuesta es siempre el mismo. Los valores ausentes llegan como `null`, así que no hacen falta comprobaciones de `undefined` ni de existencia de clave.
* `0` es un valor válido para `policy.*.threshold`. No use una comprobación de tipo falsy para decidir si una política está configurada: use `enabled`.
* Los campos de tipo arreglo son `null`, no un arreglo vacío, cuando no hay valor. Aplique un valor por defecto con `?? []` o compruebe `!== null` antes de recorrerlos.
* Los objetos anidados (`occluded`, `faceCover`, `headCover`, `signals`) son `null` en su totalidad cuando no corresponden. Compruebe si el padre es `null` antes de leer sus propiedades.
* Cuando el umbral y la puntuación son iguales, se considera que el umbral se cumple.
* Las puntuaciones pueden incluir decimales en lugar de ser enteros. Procéselas como números, no como cadenas.

## Respuestas de error

Los errores que devuelve la aplicación de ARGOS usan el formato siguiente.

```json error.json theme={null}
{
  "code": "REQUEST_INVALID",
  "message": "limit must be a decimal integer between 10 and 200."
}
```

<ResponseField name="code" type="string">
  Código de error. Bifurque con este valor y no con el código de estado HTTP.
</ResponseField>

<ResponseField name="message" type="string">
  Descripción legible por personas. El texto puede cambiar sin previo aviso, así que nunca bifurque comparando cadenas.
</ResponseField>

El objeto de error tiene exactamente dos campos: `code` y `message`.

### Errores de la capa de autenticación (401, 403)

<Warning>
  **Las solicitudes bloqueadas en la capa de autenticación no siguen el formato `{ code, message }`.**

  La validación de la clave API ocurre en la capa de autenticación, antes de que la solicitud llegue a la aplicación de ARGOS. Las respuestas bloqueadas en esa fase no tienen campo `code`.
</Warning>

| Situación                                                 | Estado HTTP | Cuerpo de la respuesta                           |
| --------------------------------------------------------- | ----------- | ------------------------------------------------ |
| No se envía clave API                                     | `401`       | `{ "message": "Unauthorized" }`                  |
| Clave API inexistente o no válida                         | `403`       | `{ "message": "..." }`                           |
| Clave API válida pero no vinculada a un proyecto FaceAuth | `403`       | `{ "code": "AUTH_FORBIDDEN", "message": "..." }` |

* **Trate el `401` y el `403` de la capa de autenticación por estado HTTP, no por `code`.** Ninguna de las dos respuestas tiene campo `code`.
* El `403` tiene dos causas con formatos de respuesta distintos. Si hay campo `code`, lo devolvió la aplicación; si no lo hay, lo bloqueó la capa de autenticación.
* El `message` de un error de la capa de autenticación no lo genera ARGOS y puede cambiar sin previo aviso. No lo procese.

<Note>
  Al notificar una consulta técnica o una incidencia, incluya la hora de la solicitud (UTC), el endpoint invocado y los cuatro primeros caracteres de la clave API utilizada.
</Note>

### Lista de códigos de error

| Estado HTTP | code                            | Condición                                                                                             | Endpoints                           |
| ----------- | ------------------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `400`       | `REQUEST_INVALID`               | La solicitud no es válida. Consulte la sección de errores de cada página de endpoint.                 | Todos                               |
| `400`       | `FACEAUTH_FACE_NOT_DETECTED`    | No se encontró un rostro comparable en la imagen facial.                                              | POST                                |
| `403`       | `AUTH_FORBIDDEN`                | La clave API es válida pero no está vinculada a un proyecto FaceAuth.                                 | Todos                               |
| `404`       | `FACEAUTH_SUBMISSION_NOT_FOUND` | No se encuentra el `authId` en este proyecto.                                                         | Consulta individual, imagen, DELETE |
| `404`       | `SUBMISSION_NOT_FOUND`          | El envío KYC no existe, se eliminó o pertenece a otro proyecto.                                       | POST                                |
| `409`       | `SUBMISSION_NOT_APPROVED`       | El envío KYC no está aprobado o no tiene imagen de referencia.                                        | POST                                |
| `503`       | `UPSTREAM_UNAVAILABLE`          | Un servicio interno no está disponible temporalmente. Reintente la misma solicitud en unos instantes. | Todos                               |
| `503`       | `UPSTREAM_INVALID_RESPONSE`     | El resultado interno de la consulta no puede convertirse al contrato público.                         | Consulta de lista e individual      |
| `500`       | `INTERNAL_UNEXPECTED`           | Error inesperado del servidor.                                                                        | Todos                               |

## Migrar desde la API anterior

Si su integración usa el endpoint anterior `/v3/faceauth`, revise los cambios siguientes. **Han cambiado las rutas, los nombres de los campos, los sobres de respuesta y el formato de error.**

### Endpoints

| Operación           | API anterior                        | API nueva                          |
| ------------------- | ----------------------------------- | ---------------------------------- |
| Crear un envío      | `POST /v3/faceauth`                 | `POST /v3/face-auth`               |
| Consulta de lista   | `GET /v3/faceauth`                  | `GET /v3/face-auth`                |
| Consulta individual | `GET /v3/faceauth?authId=...`       | `GET /v3/face-auth/{authId}`       |
| Descarga de imagen  | `GET /v3/faceauth/image?authId=...` | `GET /v3/face-auth/{authId}/image` |
| Eliminar un envío   | `DELETE /v3/faceauth?authId=...`    | `DELETE /v3/face-auth/{authId}`    |

`authId` pasa a ser un **parámetro de ruta** en lugar de un parámetro de consulta, y la consulta de lista y la individual son **endpoints separados**.

### Sobres de respuesta

| Caso                 | API anterior                                            | API nueva                                      |
| -------------------- | ------------------------------------------------------- | ---------------------------------------------- |
| Consulta individual  | `{ faceAuth_projectId, data: [ {...} ] }`               | El objeto del envío en el nivel superior       |
| Consulta de lista    | `{ faceAuth_projectId, data: { items, nextPage_key } }` | `{ items, nextCursor }`                        |
| `authId` inexistente | `200` con `data: []`                                    | `404 FACEAUTH_SUBMISSION_NOT_FOUND`            |
| Crear un envío       | `200` con `{ score, authentication_id, ... }`           | `201 Created` con el objeto FaceAuthSubmission |
| Eliminar un envío    | `{ "result": "success", "statusCode": 200 }`            | `{ "authId": "..." }`                          |

`faceAuth_projectId` y `statusCode` se han eliminado de las respuestas.

### Nombres de campos

| API anterior                                 | API nueva                                        |
| -------------------------------------------- | ------------------------------------------------ |
| `auth_id` / `authentication_id` (POST)       | `authId`                                         |
| `auth_status`                                | `authStatus`                                     |
| `create_time`                                | `createTime`                                     |
| `submit_type`                                | `submitType`                                     |
| `kyc_submission_id`                          | `kycSubmissionId`                                |
| `reject_comment` / `rejected_comment` (POST) | `rejectComment`                                  |
| `fail_code`                                  | `failCode`                                       |
| `score` (POST, snake\_case)                  | `result` (camelCase, igual que en las consultas) |
| `delete_check` + `delete_time`               | Solo `deleteTime` (`null` antes de eliminar)     |

### Cambios estructurales

<AccordionGroup>
  <Accordion title="policy: de umbrales planos a objetos anidados">
    La API anterior llevaba los umbrales planos, como en `faceSimilarity_threshold: 85`, y solo `occluded_threshold` era un `boolean`.

    La API nueva da a cada elemento un objeto `{ enabled, threshold }`. **Si una política se aplicó se determina con `enabled`, no con el valor de `threshold`.** `occluded` no usa criterio numérico, así que su `threshold` es siempre `null`.

    ```json API anterior theme={null}
    { "faceSimilarity_threshold": 85, "occluded_threshold": true }
    ```

    ```json API nueva theme={null}
    {
      "faceSimilarity": { "enabled": true, "threshold": 85 },
      "occluded": { "enabled": true, "threshold": null }
    }
    ```
  </Accordion>

  <Accordion title="result: occluded, faceCover y headCover pasan a ser objetos">
    La API anterior devolvía un único valor, como `occluded: false` (boolean) o `headCover: 0` (number). En la API nueva los tres son objetos `{ value, confidence }`, y el objeto completo es `null` cuando la comprobación no se ejecutó.

    ```json API nueva theme={null}
    { "occluded": { "value": false, "confidence": 99.2 }, "faceCover": null }
    ```
  </Accordion>

  <Accordion title="Paginación: de una clave compuesta a un único cursor">
    La API anterior devolvía `nextPage_key` y esperaba de vuelta su `authId` y su `createTime` como `nextKey_id` y `nextKey_date`, con el tamaño de página en `count` (1–2.000, valor predeterminado 2.000).

    La API nueva devuelve una única cadena firmada, `nextCursor`, que se reenvía tal cual en `cursor`, con el tamaño de página en `limit` (10–200, valor predeterminado 100). Un `limit` fuera de rango ya no se ignora: devuelve `400 REQUEST_INVALID`.
  </Accordion>

  <Accordion title="Descarga de imagen: del cuerpo binario a una redirección 302">
    La API anterior devolvía el binario JPEG directamente en el cuerpo de la respuesta. La API nueva devuelve `302 Found` con una URL de descarga de vida corta en el encabezado `Location`, así que el **cliente HTTP debe estar configurado para seguir redirecciones** (`curl --location`).
  </Accordion>

  <Accordion title="Formato de error: de tres formatos a uno">
    La API anterior mezclaba `{ message, errorCode, statusCode }`, `{ traceId, errorCode, message }` y `{ message, statusCode }` según el endpoint, y el endpoint de imagen devolvía `403` para cualquier fallo de autenticación.

    La API nueva devuelve todos los errores de aplicación como `{ code, message }`, con los errores de la capa de autenticación como única excepción. Consulte [Respuestas de error](#respuestas-de-error) más arriba.
  </Accordion>
</AccordionGroup>

### El cambio que más conviene vigilar

<Warning>
  **La API anterior eliminaba de la respuesta las claves de las opciones no utilizadas; la API nueva incluye siempre la clave y rellena el valor con `null`.**

  El código escrito para la API anterior que decide si una política se usó a partir de la existencia de la clave — `if (result.headCover)` o `'headCover' in result` — **funciona mal con la API nueva.** Use `result.headCover !== null` (si se ejecutó) o `policy.headCover.enabled` (si está configurada) en su lugar.
</Warning>
