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

# Verificar por Proveedor Externo

> Envía a Fluz un resultado KYC ya decisionado de tu propio proveedor de verificación de identidad en lugar de que Fluz ejecute la verificación.

Si tu plataforma ya ejecuta KYC con su propio proveedor de identidad, tus clientes no deberían tener que verificarse dos veces. Envía el resultado decisionado a Fluz con `postKycVerification`.

A diferencia de los otros métodos de la API, Fluz no evalúa la identidad en sí aquí: la decisión es tuya. Fluz solo la valida y la registra, y actualiza el estado del cliente en consecuencia.

<Info>
  **Requisitos previos**

  * Un programa de KYC externo aprobado por Fluz para tu aplicación. Habla con tu gerente de cuenta antes de implementar contra este método.
  * El alcance `VERIFY_KYC` habilitado en tu aplicación por Fluz. Consulta [Alcance requerido](/user-kyc-verification#required-scope).
  * Un [token de acceso de usuario](/recipes/generate-user-access-token) generado para el cliente que se está verificando, que incluya `VERIFY_KYC` en sus alcances.
  * El endpoint dedicado de ingesta segura para tu entorno, proporcionado durante la incorporación.
</Info>

<Warning>
  Envía esta mutación al **endpoint dedicado de ingesta segura**, no al host estándar de la API. Este endpoint tokeniza de forma segura datos PII como `person.ssn` en tránsito. Una solicitud cuyo SSN u otros datos PII lleguen sin tokenizar será rechazada. Pasa siempre los argumentos como **variables** de GraphQL; los valores incluidos inline en el documento de la consulta no pueden tokenizarse.

  * Staging: `https://secure.transactional-graph.staging.fluzapp.com/api/v1/graphql`
  * Producción: proporcionado durante la incorporación
</Warning>

## Cómo funciona

La mutación `postKycVerification` es sincrónica. Envías la identidad verificada y las verificaciones del proveedor que respaldan tu decisión, y Fluz devuelve `APPROVED`, `DECLINED`, `DUPLICATE` o `ERROR` en el cuerpo de la respuesta. No hay paso de cara al cliente.

Algunos comportamientos son específicos de este método:

* **Solo resultados decisionados.** `decision` debe ser `PASSED` o `FAILED`. No envíes verificaciones pendientes o sin decisión.
* **Idempotencia.** Las presentaciones son idempotentes sobre `externalVerificationId` — el id único global de tu proveedor para el intento. Repetir un id devuelve el resultado original y no escribe nada; una verificación re-decisionada debe enviarse con un id nuevo.
* **Transiciones de estado.** Un resultado `PASSED` mueve a un cliente no verificado a verificado. Si el cliente ya está verificado — por cualquier método — la verificación igualmente se registra para auditoría, pero su estado nunca cambia; el mensaje de la respuesta indica que se preservó el estado existente. Un resultado `FAILED` se registra y deja el estado sin cambios.
* **Sin límite de intentos.** Debido a que estás reportando resultados en lugar de solicitar un screening, este método no tiene límite de intentos y no cuenta contra los límites de [Verificar por SSN](/verify-customers-by-ssn) o [KYC Autofill](/verify-customers-by-autofill).

## Solicitud

El cliente se identifica por el token de acceso del usuario en el encabezado `Authorization` — `person.userId` y la identidad de tu aplicación los completa Fluz, y cualquier valor enviado se sobrescribe.

| Campo                          | Tipo   | Requerido | Descripción                                                                                                  |
| :----------------------------- | :----- | :-------- | :----------------------------------------------------------------------------------------------------------- |
| `schemaVersion`                | String | Sí        | Versión del contrato del payload. Actualmente `"1.0"`.                                                       |
| `externalVerificationProvider` | String | Sí        | `IDOLOGY`, `OSCILAR`, `PERSONA` o `CUSTOM`.                                                                  |
| `externalVerificationId`       | String | Sí        | El id único global de tu proveedor para este intento — la clave de idempotencia.                             |
| `decision`                     | String | Sí        | `PASSED` o `FAILED`.                                                                                         |
| `decisionReason`               | String | No        | Motivo legible por humanos o regla que produjo la decisión.                                                  |
| `decisionedAt`                 | String | No        | Marca de tiempo ISO 8601 de la decisión. De forma predeterminada, el momento de la ingesta.                  |
| `person`                       | JSON   | Sí        | La identidad verificada según lo establecido por el proveedor.                                               |
| `verifications`                | JSON   | Sí        | Las verificaciones del proveedor que respaldan la decisión — al menos una de `document`, `ssn` o `database`. |
| `externalProviderData`         | JSON   | No        | Contexto libre del proveedor para auditoría.                                                                 |

Consulta [postKycVerification](/api-reference/mutations/post-kyc-verification) para la referencia completa de campos, incluidas las estructuras de los objetos `person` y `verifications`.

## Ejemplo

```javascript theme={null}
import { GraphQLClient, gql } from 'graphql-request';

const API_URL =
  'https://secure.transactional-graph.staging.fluzapp.com/api/v1/graphql';

const POST_KYC_VERIFICATION = gql`
  mutation postKycVerification(
    $schemaVersion: String!
    $externalVerificationProvider: String!
    $externalVerificationId: String!
    $decision: String!
    $decisionReason: String
    $person: JSON!
    $verifications: JSON!
  ) {
    postKycVerification(
      schemaVersion: $schemaVersion
      externalVerificationProvider: $externalVerificationProvider
      externalVerificationId: $externalVerificationId
      decision: $decision
      decisionReason: $decisionReason
      person: $person
      verifications: $verifications
    ) {
      status
      verificationId
      message
    }
  }
`;

const client = new GraphQLClient(API_URL, {
  headers: {
    Authorization: `Bearer <<USER_ACCESS_TOKEN>>`,
    'Content-Type': 'application/json',
  },
});

const response = await client.request(POST_KYC_VERIFICATION, {
  schemaVersion: '1.0',
  externalVerificationProvider: 'PERSONA',
  externalVerificationId: 'inq_gCf28LrXY9wrxDoZbnbEqTrn',
  decision: 'PASSED',
  decisionReason: 'All checks passed',
  person: {
    firstName: 'JANE Q',
    lastName: 'SAMPLE',
    dateOfBirth: '1990-01-01',
    ssn: '900-98-7654',
    ssnLast4: '7654',
    address: {
      streetLine1: '123 EXAMPLE STREET',
      city: 'SAMPLETOWN',
      subdivision: 'CA',
      postalCode: '90001',
      countryCode: 'US',
    },
  },
  verifications: {
    document: {
      verificationId: 'ver_p8qmKydzkQwyLKbaAJRvADi9',
      status: 'PASSED',
      documentClass: 'DRIVER_LICENSE',
      documentNumber: 'X90000000000001',
      issuingCountryCode: 'US',
      photos: { front: 'https://files.provider.example/front.jpg' },
      checks: [{ name: 'id_expired_detection', status: 'PASSED' }],
    },
    ssn: {
      verificationId: 'ver_tin_snW2CvL2x4kTdZjbmGBjqcuV',
      status: 'PASSED',
      source: 'TIN_DATABASE',
    },
  },
});

console.log(response);
```

```json Response theme={null}
{
  "data": {
    "postKycVerification": {
      "status": "APPROVED",
      "verificationId": "4b99e8c5-4201-45fd-a5dc-1c3b88e4f6c7",
      "message": "User verification successful"
    }
  }
}
```

## Manejo de la respuesta

| Estado      | Qué hacer                                                                                                                                                                                                                                |
| :---------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `APPROVED`  | La verificación fue registrada. Si el cliente aún no estaba verificado, ahora lo está; si ya estaba verificado, `message` indica que se preservó el estado existente.                                                                    |
| `DECLINED`  | Se registró el resultado `FAILED`. El estado del cliente no cambia.                                                                                                                                                                      |
| `DUPLICATE` | La verificación fue registrada, pero el SSN o número de documento coincide con otro cliente de Fluz. La cuenta se pone en revisión — investiga de tu lado antes de proceder. Fluz no divulga con qué cliente se produjo la coincidencia. |
| `ERROR`     | Revisa `message` — comúnmente un payload que no cumplió la validación del contrato. No se registró nada.                                                                                                                                 |

## Pruebas

Prueba contra el endpoint de staging con identidades fabricadas: dado que la decisión es tuya, no hay requisitos de identidades de prueba del proveedor como con los otros métodos. Usa SSNs en el rango `900-XX-XXXX` (nunca emitidos), genera un `externalVerificationId` nuevo por intento (repetir un id devuelve el resultado original en lugar de ejercitar uno nuevo), y asegúrate de que cualquier URL de foto que envíes sea accesible — Fluz recupera y almacena las imágenes.
