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

# API de Travel Rule del GAFI: cumplimiento para VASP

> Travel Rule del GAFI con Didit para VASP y PSP: intercambio de datos de ordenante y beneficiario y remediación automática. $0.02 por intercambio.

Didit ejecuta el intercambio de datos entre ordenante y beneficiario que exigen el GAFI y el Reglamento de Transferencias de Fondos de la UE (TFR) para las transferencias de activos virtuales: busca un canal que llegue al VASP de la contraparte, negocia por él los datos requeridos, sigue el intercambio a lo largo de un ciclo de vida de 13 estados y te avisa cuando el intercambio ha concluido para que puedas liberar los fondos on-chain.

## Descripción general

La Travel Rule del GAFI (Recomendación 16), que en la UE se aplica mediante el Reglamento de Transferencias de Fondos (TFR), exige que el proveedor de servicios de activos virtuales que envía (el **VASP ordenante**) recopile y transmita la información del ordenante y del beneficiario al VASP que recibe (el **VASP beneficiario**) antes de que se liquide una transferencia de activos virtuales.

A diferencia de la mayoría de las jurisdicciones, el TFR de la UE se aplica **sin importe mínimo**: todas las transferencias de criptoactivos están dentro del alcance, no solo las que superan un umbral de reporte.

El producto Travel Rule de Didit es un intercambio gestionado, no un simple campo de datos:

* Envías una transferencia con `transaction_category: "travelRule"`.
* Didit prueba los canales por orden de prioridad para llegar al VASP de la contraparte, realiza el intercambio por el primero que lo alcanza y, cuando la otra parte devuelve un nombre del beneficiario, lo compara con el que enviaste.
* Solo debes emitir la transferencia on-chain cuando el intercambio llegue a `COMPLETED`.
* Después, comunicas a Didit el hash de la transacción on-chain para cerrar el intercambio como `FINISHED`.

Esta versión incluye siete canales, que se prueban en estricto orden de prioridad: gana el primero que puede llegar a la contraparte.

| Prioridad | Canal | Cómo funciona |
| - | - | - |
| 1 | `INTERNAL` | Se usa cuando otro cliente de Didit ha demostrado el control de la wallet del beneficiario con un mensaje firmado o un depósito de prueba. Didit crea una transferencia entrante equivalente en la aplicación de ese cliente y negocia el intercambio íntegramente dentro de la plataforma, sin ninguna llamada de red saliente. Instantáneo. |
| 2 | `TRP` | Integración nativa con el protocolo abierto Travel Rule Protocol (TRP / OpenVASP). Se usa cuando la transferencia lleva una [Travel Address](#direcciones-de-viaje), cuando la entrada de la libreta de direcciones de la wallet de destino tiene una guardada o cuando el VASP de la contraparte se resuelve en el [directorio](#directorio) con un endpoint TRP. Incluye los activos enumerados en [Identificadores de activos TRP](#identificadores-de-activos-de-trp). Didit intercambia los datos del ordenante y del beneficiario de máquina a máquina, sin idas y vueltas por correo electrónico. |
| 3 | `GTR` | Red Global Travel Rule (GTR). La contraparte se resuelve mediante un `counterparty_gtr_vasp_code` explícito o una entrada del directorio que lo incluya. Didit lee la respuesta de la contraparte en la respuesta de GTR, o consultando el estado de la solicitud cada 5 minutos mientras la transferencia espera. |
| 4 | `TRUST` | Red TRUST. La contraparte se resuelve mediante `counterparty_trust_membership_id` o una entrada del directorio que lo incluya. Solo envío: TRUST no devuelve nada que Didit pueda leer, por lo que la transferencia permanece en `AWAITING_COUNTERPARTY` hasta que expira. |
| 5 | `VERIFYVASP` | Red VerifyVASP. La contraparte se resuelve mediante `counterparty_verifyvasp_id` o una entrada del directorio que lo incluya. Didit lee la respuesta de la contraparte consultando el estado de la verificación cada 5 minutos. |
| 6 | `SYGNA` | Red Sygna Bridge (adquirida por VerifyVASP en 2026; sigue operando para los miembros existentes). Implementación nativa del protocolo Sygna: IVMS101 cifrado con ECIES y solicitudes de permiso firmadas. La contraparte se resuelve mediante `counterparty_sygna_vasp_code` o una entrada del directorio que lo incluya. La respuesta de aceptación o rechazo de la contraparte completa o rechaza la transferencia: Didit consulta el estado de la transferencia cada 5 minutos y, además, recibe la respuesta en su callback de Sygna una vez que el host TRP público de Didit esté activo. |
| 7 | `EMAIL` | Alternativa que se usa cuando ningún canal de protocolo o de red llega a la contraparte y tú indicas su contacto de cumplimiento en `counterparty_vasp_email`, o cuando la entrada de la contraparte en el directorio tiene un [contacto de cumplimiento](#contactos). Didit envía a ese contacto por correo electrónico un enlace de recogida de un solo uso para que pueda confirmar o rechazar el intercambio sin una cuenta de Didit. Es el canal principal para el problema del sunrise: contrapartes que todavía no son accesibles en ninguna red. |

Los canales de red (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) requieren una membresía de red en el lado emisor y, hoy por hoy, esa membresía tiene que ser **tuya**.
Conecta las credenciales de tu membresía en **Marketplace** de la consola (categoría de redes Travel Rule), y tus transferencias viajarán con tu propia identidad de red.

**Hoy Didit no tiene membresía de plataforma en ninguna de las cuatro redes y está en proceso de incorporarse como proveedor en ellas.**
Hasta que esa incorporación se complete, `platform_available` es `false` en las cuatro, el modo `didit` de la configuración (enrutar a través de la membresía de plataforma de Didit) no está disponible para ninguna red y `disabled_networks` no tiene nada que desactivar.
Una membresía que conectes tú siempre tiene prioridad sobre una membresía de plataforma.
No se incluye ninguna membresía de red por defecto, tampoco la de GTR.
Activar Travel Rule no activa GTR, TRUST, VerifyVASP ni Sygna.
Consulta [Obtener la configuración de Travel Rule](https://docs.didit.me/es/management-api/travel-rule/get-settings.md) para ver los modos `networks` vigentes de tu aplicación, y [Redes Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md) para saber a quién llega cada red hoy.
Si las cuatro indican `unavailable`, ninguna puede enrutar un intercambio: conecta tu propia membresía en **Marketplace** o usa una contraparte accesible por `INTERNAL`, `TRP` o `EMAIL`.

Cuando guardas una membresía, su código de participante debe ser el tuyo: al guardar se devuelve un `400` cuando el código es el propio código de Didit en esa red o un código que ya tiene la membresía de otra aplicación.
Una membresía de GTR necesita su clave privada ed25519 (en base64), aquella cuya clave pública está registrada en el portal de GTR: cifra los datos personales que envías y descifra los datos que recibes.
Una membresía de VerifyVASP apunta a tu propio VerifyVASP Enclave: su URL es la de tu Enclave y su token es el que tu Enclave presenta a Didit.

Incluso con tu propia membresía, un canal de red solo enruta una transferencia cuando su `beneficiary_data` lleva el identificador de la contraparte en esa red (`counterparty_gtr_vasp_code`, `counterparty_trust_membership_id`, `counterparty_verifyvasp_id` o `counterparty_sygna_vasp_code`), o cuando la entrada de la contraparte en el directorio la incluye en esa red (consulta [Rutas](#rutas)).

`platform_available` indica si la membresía de plataforma está configurada; no es una comprobación en vivo del estado de la red. Del mismo modo, `connected` significa que las credenciales de tu membresía están guardadas y han superado la validación local; el primer intercambio real las verifica frente a la red. Un modo `didit` u `own` no garantiza que la contraparte sea accesible ni que la entrega se realice correctamente.

Con tu propia membresía, Didit lee la respuesta de la contraparte a través de `GTR`, `VERIFYVASP` y `SYGNA` a partir de la respuesta de la red o consultando la red cada 5 minutos, lo que completa o rechaza la transferencia.
`TRUST` solo envía: una transferencia enviada a través de ella permanece en `AWAITING_COUNTERPARTY` hasta que transcurre `confirmation_timeout_hours`, luego pasa a `EXPIRED` y se aplica tu `timeout_outcome`.
La recepción de una transferencia que otro VASP te envía a través de una red aún no está activada, y todavía no se ha completado ningún intercambio con una red de producción: consulta [Redes de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md).

Otras redes (CODE, la alianza coreana, TRISA, Notabene y Veriscope) aparecen en el **Marketplace** de la consola como tarjetas de solicitud de acceso.
Didit aún no tiene integración con ellas, por lo que hoy ninguna transferencia puede enrutarse a través de ellas.

Cuando ninguno de los siete canales puede resolver una contraparte, Didit ejecuta un paso de resolución más antes de darse por vencido: la atribución mediante análisis de blockchain.
La wallet de destino se busca en los datos de análisis de blockchain; cuando la wallet pertenece a un exchange o custodio conocido, Didit registra el VASP atribuido en la transferencia, lo añade al [directorio](#directorio) y vuelve a ejecutar los canales una vez con el nuevo nombre.
Consulta [Atribución mediante análisis de blockchain](#atribución-mediante-análisis-de-blockchain) para conocer el comportamiento completo y los precios.

Una transferencia cuyo destino está [declarado como wallet sin custodia](#wallets-sin-custodia-declaradas) omite los siete canales (no hay un VASP de contraparte con el que intercambiar) y pasa directamente a la prueba de propiedad de la wallet del usuario final.

> [!NOTE]
>
> Didit también opera el lado del intercambio orientado a la contraparte: los endpoints públicos de identidad y consulta de TRP que otros VASP invocan para contactarte, los endpoints de callback y el flujo de recogida por correo electrónico.
> Nunca los invocas tú mismo, ya que son infraestructura gestionada, pero la página [Interoperabilidad de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-interoperability.md) documenta cada uno de ellos para que los VASP de contraparte puedan conectarse contigo.
> Interactúas con Travel Rule únicamente a través de los endpoints `/v3/` descritos en esta página.

## Qué se ejecuta cuando envías una transferencia

Las comprobaciones se ejecutan dentro de la única llamada `POST /v3/transactions/`: cuando recibes la respuesta, el análisis ya se ha ejecutado, la transferencia está almacenada y las reglas se han evaluado.
El intercambio en sí empieza después de la respuesta: Didit elige el canal y contacta con la contraparte fuera de tu solicitud, así que ninguna red ni contraparte puede ralentizar ni hacer fallar la creación.
Cada cambio de estado posterior llega como un webhook [`travel_rule.status.updated`](#webhooks) que indica el canal, y el objeto de transferencia que devuelven los endpoints de transferencias de Travel Rule incluye un campo [`delivery`](#entrega-y-reintentos) que muestra si el mensaje llegó.
No hay ningún proceso que debas consultar periódicamente: las partes asíncronas son el intercambio, la respuesta de la contraparte y cualquier acción del usuario final.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant You as Your platform
    participant Didit as Didit API
    participant CP as Counterparty VASP
    participant User as Your customer

    You->>Didit: POST /v3/transactions/ (travelRule)
    Note over Didit: Validate + bind subject + blocklist check
    Note over Didit: Device & IP enrichment
    Note over Didit: Crypto screening (when crypto + monitoring on)
    Note over Didit: Threshold check -> transfer stored (AWAITING_COUNTERPARTY)
    Note over Didit: Rules engine (EU TFR bundle + your rules)
    Didit--)You: transaction.created webhook
    Didit-->>You: Transaction + travel_rule.status + action_required
    Note over Didit: After the response: rails in priority order -> analytics attribution
    Didit->>CP: Exchange over the first reachable rail
    Didit--)You: travel_rule.status.updated (each status change)
    User->>Didit: Proves wallet control (when action_required)
    CP-->>Didit: Confirms beneficiary data
    Didit--)You: travel_rule.status.updated (COMPLETED)
    You->>You: Broadcast on-chain
    You->>Didit: PATCH .../travel-rule/ { payment_txn_id }
    Didit--)You: travel_rule.status.updated (FINISHED)
```

Paso a paso:

1. **Validación y vinculación del sujeto.** Se valida el payload.
   Un `transaction_id` que ya se ha usado en tu aplicación se rechaza con `400` y, cuando dos solicitudes con el mismo id compiten, una de ellas recibe `409`.
   El `subject` se vincula a tu perfil de usuario o de empresa mediante `vendor_data`, de modo que la transferencia aparece en ese perfil para su monitorización.
   Un `vendor_data` de sujeto o de contraparte incluido en la lista de bloqueo se rechaza con `400` y no se crea ninguna transacción.
   Las wallets, cuentas bancarias, IP y dispositivos incluidos en la lista de bloqueo se comprueban en el paso 6 y provocan el rechazo de la transacción en ese punto, después de que se haya ejecutado el enrutamiento.
2. **Enriquecimiento de dispositivo y red.** Las IP de las partes se enriquecen con geolocalización, y cualquier contexto de dispositivo (automático con el [envío desde el SDK](https://docs.didit.me/es/transaction-monitoring/sdk-transaction-submission.md)) se normaliza en el grafo de dispositivos, el mismo grafo que alimentan las sesiones de KYC, de modo que "relacionado por dispositivo" funciona tanto en el onboarding como en las transacciones.
3. **Análisis cripto.** En las transferencias cripto con la monitorización activada, la wallet correspondiente (o el hash on-chain) se analiza con analítica de blockchain antes de intercambiar nada: exposición a sanciones, proximidad a mezcladores y fondos robados. Consulta [Análisis cripto y de wallets](https://docs.didit.me/es/transaction-monitoring/aml-screening.md).
4. **Transferencia de Travel Rule.** El motor de intercambio comprueba el umbral y respeta una [declaración de wallet sin custodia](#wallets-sin-custodia-declaradas), y luego almacena la transferencia: `NOT_APPLICABLE` por debajo de tu umbral, `UNCONFIRMED_OWNERSHIP` para una wallet sin custodia declarada, `COMPLETED` cuando la otra wallet es tu propia wallet verificada, y `AWAITING_COUNTERPARTY` en los demás casos, todavía sin canal.
   Cada cambio de estado pone en cola un evento `travel_rule.status.updated`, y Didit lo envía después del `transaction.created` de la transacción (paso 7).
5. **Creación de la verificación de propiedad de la wallet.** Si la transferencia requiere que el usuario final demuestre el control y `auto_wallet_verification` está activado, se crea una sesión del [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) y se devuelve en `action_required`.
6. **Evaluación de reglas.** Se ejecutan todas las reglas activas: el [paquete EU TFR](#paquete-de-reglas-eu-tfr) reacciona al estado de la transferencia fijado en el paso 4, tus reglas personalizadas ven el resultado del análisis del paso 3, y una regla puede retener la transacción (`IN_REVIEW`), rechazarla o exigir una [verificación adicional](https://docs.didit.me/es/transaction-monitoring/sdk-transaction-submission.md#acciones-requeridas-del-usuario) (`AWAITING_USER`).
7. **Facturación y notificación.** Una transacción saliente se factura en una sola línea: la [línea de Travel Rule](#precios) cuando inició un intercambio y Transaction Screening en caso contrario. Una transferencia entrante no conlleva ninguna de las dos tarifas, y a una aplicación de sandbox nunca se le cobra.
   Se devuelve la respuesta y `transaction.created` se envía a tus destinos de webhook, seguido de los eventos `travel_rule.status.updated` del paso 4.
8. **Enrutamiento, después de la respuesta.** Didit recorre los [siete canales](#descripción-general) por orden de prioridad; si ninguno resuelve, la [atribución mediante analítica de blockchain](#atribución-mediante-análisis-de-blockchain) identifica a la contraparte y se vuelve a intentar el enrutamiento por los canales una vez. El primer canal disponible se encarga del intercambio: la transferencia permanece en `AWAITING_COUNTERPARTY` en ese canal mientras la contraparte responde, se liquida de inmediato cuando se identifica una contraparte `INTERNAL` (`COMPLETED` o `COUNTERPARTY_MISMATCHED_DATA`), o pasa a `COUNTERPARTY_VASP_NOT_FOUND` cuando ningún canal llega a la contraparte. Cada cambio envía `travel_rule.status.updated`, y tus reglas se vuelven a ejecutar siempre que cambian el estado o el canal. Una transferencia que el enrutamiento deja en `COUNTERPARTY_VASP_NOT_FOUND` recibe en ese momento su sesión del widget de propiedad de wallet (cuando `auto_wallet_verification` está activado); consúltala en el `action_required` de la transacción con [Obtener transacción](https://docs.didit.me/es/management-api/transactions/get.md).

### Cómo se corresponde cada paso con tus obligaciones

| Paso del proceso | Obligación que cumple |
| - | - |
| Datos del ordenante que proporcionas en `originator_data` | Información exacta del ordenante (FATF R.16; EU TFR art. 14). En los canales que transportan datos personales (`INTERNAL`, `TRP` y los canales de red), Didit transmite la identidad verificada cuando el sujeto es un usuario con una verificación KYC de Didit aprobada (consulta [Datos verificados y procedencia](#datos-verificados-y-procedencia)) y, en caso contrario, exactamente el `originator_data` que envías. |
| Intercambio por canales antes de la liquidación | Información del ordenante y del beneficiario transmitida al VASP de la contraparte **antes** de que se liquide la transferencia (FATF R.16; EU TFR art. 14-16) |
| Coincidencia del nombre del beneficiario | Verificación de que los datos del beneficiario coinciden con el destino (obligaciones del CASP del beneficiario según el art. 16 del EU TFR) |
| Prueba de propiedad de wallet sin custodia | La obligación del EU TFR sobre wallets sin custodia: verificar la propiedad de una dirección sin custodia en lugar de realizar el intercambio con un VASP |
| Análisis cripto + paquete de reglas EU TFR | Procedimientos basados en el riesgo para transferencias con información ausente o incompleta, y controles de exposición a sanciones |
| Control `COMPLETED` antes de la difusión | Los fondos no se liberan hasta que concluye el intercambio: el núcleo de la norma |
| Cierre `FINISHED` con el hash on-chain + cronología | Conservación de registros: cada transferencia incluye su cronología completa de negociación para auditoría |

> [!NOTE]
>
> **Nota sobre pruebas.** Las aplicaciones de sandbox omiten la evaluación de reglas y la facturación, y no envían webhooks `transaction.created` ni `transaction.status.updated`. Las transacciones de sandbox permanecen en `APPROVED` salvo que una transferencia de Travel Rule que expira aplique tu `timeout_outcome`, y no se cobra nada.
> El propio motor de intercambio de Travel Rule se ejecuta en las aplicaciones de sandbox cuando Travel Rule está activado, frente a una única contraparte: todo intercambio **saliente** va al [VASP de prueba de Didit](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) en el canal `TEST_VASP`, que responde dentro de Didit con el escenario que elijas, de modo que la transferencia se completa, se rechaza, presenta datos no coincidentes, la contraparte no está disponible, expira o queda a la espera de que se demuestre la propiedad de la wallet.
> Ningún mensaje de cumplimiento llega nunca a un VASP de contraparte real, y los webhooks `travel_rule.status.updated` se entregan con `environment: sandbox`.
> **Entrante**: el VASP de prueba puede enviarte una transferencia ([Disparar transferencia entrante del VASP de prueba](https://docs.didit.me/es/management-api/travel-rule/trigger-test-vasp-inbound.md)), y el registro (`POST /v3/travel-rule/inbound/`) se resuelve frente a tu libreta de direcciones de wallets igual que en una aplicación de producción: `ON_HOLD`, `UNCONFIRMED_OWNERSHIP`, `COUNTERPARTY_MISMATCHED_DATA`, o `COMPLETED` y después `FINISHED`.
> Consulta [Probar Travel Rule en sandbox](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md).

## Ciclo de vida

Cada transferencia tiene un `status` que toma uno de 13 valores.
El intercambio empieza en `AWAITING_COUNTERPARTY` en el caso normal, en `NOT_APPLICABLE` cuando el importe está por debajo de tu `threshold_amount` o una solicitud de pago de Lightning no indica beneficiario (consulta [Lightning](#lightning)), o en `UNCONFIRMED_OWNERSHIP` cuando el destino se [declaró como wallet sin custodia](#wallets-sin-custodia-declaradas), y termina en uno de los estados finales: `FINISHED`, `CANCELLED` o `EXPIRED`.

La transferencia ejecuta su propia máquina de estados, **independiente del** estado de revisión de la transacción subyacente.
Un estado del intercambio nunca cambia por sí solo el estado de la transacción, con una excepción: una expiración aplica el `timeout_outcome` que hayas configurado (o una [política de periodo de transición o de contraparte sin respuesta](#políticas-de-periodo-de-transición-y-de-falta-de-respuesta) cuando corresponda).
En cambio, tus reglas se vuelven a ejecutar en cada transición, de modo que las [reglas de la TFR de la UE](#paquete-de-reglas-eu-tfr) o cualquier regla basada en `travel_rule_status` pueden mover la transacción, por ejemplo a `IN_REVIEW`.
Una transferencia que necesita que el usuario final demuestre el control de la wallet añade un bloque `action_required` a la transacción, pero su `status` se mantiene tal como lo dejaron tus reglas.
Lee el estado del intercambio en `travel_rule.status`; lee el veredicto de permitir / retener / rechazar en el propio `status` de la transacción.

Cada transición (y cada estado notificado de forma pasiva) también se refleja en los valores personalizados de la transacción para que las [reglas](https://docs.didit.me/es/transaction-monitoring/rules.md) puedan basarse en él: `custom_values.travel_rule_status` (estado canónico), `custom_values.travel_rule_rail` (el canal que transportó el intercambio, vacío hasta que se selecciona uno) y `custom_values.travel_rule_regime` (derivado del `jurisdiction` de tu [configuración](#configuración): `SG` → `singapore`, `GB` → `uk`, y cualquier código de un miembro de la UE o del EEE, como `DE` o `FR` → `eu`; los códigos sin correspondencia se registran en minúsculas, p. ej., `US` → `us`. Un `props.travel_rule_regime` que envíes tú siempre prevalece sobre el valor derivado).

| Estado | Significado |
| - | - |
| `AWAITING_COUNTERPARTY` | La transferencia espera a su contraparte: primero mientras Didit elige el canal y envía el intercambio, justo después de la creación, y después mientras la contraparte responde. La [`delivery`](#entrega-y-reintentos) de la transferencia indica si el mensaje llegó. `TRUST` solo envía, así que una transferencia por ese canal permanece en este estado hasta que expira. |
| `UNCONFIRMED_OWNERSHIP` | La transferencia espera una prueba de control de la wallet. Se alcanza cuando la wallet de la contraparte se [declaró sin custodia](#wallets-sin-custodia-declaradas) en el envío (saliente o entrante), o cuando una transferencia entrante se resuelve en una [entrada de la libreta de direcciones](#libreta-de-direcciones-de-wallets) cuya propiedad aún no está verificada. Avanza mediante el [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) o [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet). |
| `ON_HOLD` | Didit lo establece solo en transferencias entrantes: la wallet de destino de un [registro posterior al depósito](#registro-sunrise-posterior-al-depósito) o de una consulta `TRP` entrante no está en tu [libreta de direcciones](#libreta-de-direcciones-de-wallets), o una consulta `TRP` entrante espera tu decisión (la aceptación automática está desactivada o no se pudo entregar la respuesta automática). Resuélvelo con [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet). No cambia por sí solo el estado de la transacción; la [regla de la biblioteca](https://docs.didit.me/es/transaction-monitoring/rules-library.md) opcional `travel-rule-pending-action` mueve esas transacciones a `AWAITING_USER`. |
| `COMPLETED` | El intercambio concluyó correctamente: la contraparte (o tú, en una transferencia entrante) lo aprobó, o se superaron las comprobaciones que Didit ejecuta en esa vía (coincidencia del nombre del beneficiario, prueba de propiedad de la wallet). Es seguro difundir la transferencia on-chain. |
| `FINISHED` | El intercambio se cierra con el hash de su transacción on-chain. En una transferencia saliente, comunicas el hash mediante [`PATCH .../travel-rule/`](#enviar-una-transferencia). En una transferencia entrante, Didit lo establece cuando el depósito ya se liquidó ([registro posterior al depósito](#registro-sunrise-posterior-al-depósito)), cuando el ordenante confirma una transferencia `TRP` o cuando finaliza el lado saliente `INTERNAL`. |
| `CANCELLED` | Cancelada manualmente con `action: "cancel"` desde cualquier estado no final, o cancelada por el ordenante de una transferencia `TRP` entrante. |
| `EXPIRED` | Transcurrió `confirmation_timeout_hours` mientras estaba en `AWAITING_COUNTERPARTY`. Un proceso de barrido (cada 15 minutos) expira la transferencia y aplica el `timeout_outcome` que hayas configurado a la transacción subyacente: `REJECT` la rechaza, `HOLD` la pasa a revisión y `PROCEED` la deja intacta. Tu [política de periodo de transición o de contraparte sin respuesta](#políticas-de-periodo-de-transición-y-de-falta-de-respuesta) sustituye a `timeout_outcome` cuando corresponda. |
| `COUNTERPARTY_MISMATCHED_DATA` | El nombre del beneficiario no cumplió el `name_matching_strictness` configurado frente a la otra parte: el nombre que devolvió la contraparte o el `holder_name` de la entrada coincidente de la libreta de direcciones. |
| `COUNTERPARTY_VASP_NOT_FOUND` | Ninguno de los siete canales, ni tampoco la alternativa de [atribución mediante análisis de blockchain](#atribución-mediante-análisis-de-blockchain), pudo resolver un VASP de contraparte accesible para esta transferencia. Cualquier entidad atribuida se sigue registrando en la transferencia y en el directorio. En las transferencias salientes, Didit genera automáticamente una sesión del [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) (cuando `auto_wallet_verification` está activado) para que la transferencia aún pueda completarse como transferencia a una wallet sin custodia. `reason` y `next_actions` indican el motivo y qué la hace avanzar: consulta [Por qué una transferencia está bloqueada](#por-qué-una-transferencia-está-bloqueada). |
| `COUNTERPARTY_VASP_NOT_REACHABLE` | Se identificó un VASP de contraparte, pero el canal seleccionado no pudo entregar: no se pudo acceder a su endpoint de identidad o de consulta `TRP`, la identidad que indicó no coincidía con `counterparty_vasp_lei` o `counterparty_vasp_name`, una red rechazó el mensaje o no lo aceptó tras seis intentos (consulta [Entrega y reintentos](#entrega-y-reintentos)), o el proveedor de correo rechazó el correo electrónico de cumplimiento. `reason` distingue estos casos y `next_actions` indica qué hace avanzar la transferencia: consulta [Por qué una transferencia está bloqueada](#por-qué-una-transferencia-está-bloqueada). Reintenta con `action: "resend"` cuando vuelva a estar accesible. |
| `COUNTERPARTY_VASP_GENERAL_DECLINE` | La contraparte rechazó el intercambio: propiedad denegada, recogida por correo electrónico rechazada o un rechazo de `TRP` o de Sygna. |
| `NOT_ENOUGH_COUNTERPARTY_DATA` | Una consulta `TRP` entrante no identificó al beneficiario ni por nombre ni por dirección de wallet, por lo que Didit no pudo asociarla a tu libreta de direcciones. Ni el endpoint de propiedad ni `resend` aceptan una transferencia entrante así: solo puedes cancelarla, y cancelarla no responde a la consulta de la contraparte. Didit nunca lo establece en una transferencia saliente; si lo registras tú mismo en una, `action: "resend"` vuelve a ejecutar el enrutamiento. |
| `NOT_APPLICABLE` | El importe de la transferencia era inferior al `threshold_amount` configurado, una solicitud de pago saliente de [Lightning](#lightning) no indica ningún beneficiario (`chain_details.not_applicable_reason` explica el motivo), o registraste tú mismo este estado con Travel Rule desactivado (incluidos los valores heredados `UNKNOWN` y `EXEMPT`, consulta más abajo). |

> [!WARNING]
>
> **Nunca difundas la transacción antes de `COMPLETED`.**
> Liberar fondos on-chain mientras una transferencia está en `AWAITING_COUNTERPARTY`, `UNCONFIRMED_OWNERSHIP` o en cualquier estado de discrepancia o rechazo anula el propósito del intercambio.
> Condiciona tu paso de difusión a `status == "COMPLETED"` y, después, invoca `PATCH .../travel-rule/` con el `payment_txn_id` resultante para pasar a `FINISHED`.

Las transiciones de un vistazo (además, `CANCELLED` se puede alcanzar desde cualquier estado no terminal con `action: "cancel"`):

```mermaid theme={null}
stateDiagram-v2
    [*] --> NOT_APPLICABLE: below threshold
    [*] --> UNCONFIRMED_OWNERSHIP: self-hosted wallet declared
    [*] --> AWAITING_COUNTERPARTY: transfer stored, routing queued
    [*] --> COMPLETED: your own verified wallet
    [*] --> ON_HOLD: inbound with no matching wallet entry
    [*] --> NOT_ENOUGH_COUNTERPARTY_DATA: inbound TRP inquiry names no beneficiary
    AWAITING_COUNTERPARTY --> COUNTERPARTY_MISMATCHED_DATA: INTERNAL rail, verified entry, name mismatch
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_FOUND: no rail resolved
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_REACHABLE: delivery failed
    AWAITING_COUNTERPARTY --> COMPLETED: counterparty confirmed, names match where checked
    AWAITING_COUNTERPARTY --> COUNTERPARTY_MISMATCHED_DATA: name match failed
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_GENERAL_DECLINE: counterparty declined
    AWAITING_COUNTERPARTY --> EXPIRED: confirmation timeout
    AWAITING_COUNTERPARTY --> COUNTERPARTY_VASP_NOT_REACHABLE: TRP inquiry not delivered
    UNCONFIRMED_OWNERSHIP --> COMPLETED: ownership proven, names match
    UNCONFIRMED_OWNERSHIP --> COUNTERPARTY_MISMATCHED_DATA: name match failed
    UNCONFIRMED_OWNERSHIP --> COUNTERPARTY_VASP_GENERAL_DECLINE: ownership denied
    ON_HOLD --> COMPLETED: you confirm the wallet, names match
    ON_HOLD --> COUNTERPARTY_MISMATCHED_DATA: you confirm the wallet, name mismatch
    ON_HOLD --> COUNTERPARTY_VASP_GENERAL_DECLINE: you deny the wallet
    COUNTERPARTY_MISMATCHED_DATA --> COMPLETED: you approve an inbound TRP inquiry
    COUNTERPARTY_MISMATCHED_DATA --> COUNTERPARTY_VASP_GENERAL_DECLINE: you decline an inbound TRP inquiry
    COUNTERPARTY_VASP_NOT_FOUND --> COMPLETED: wallet ownership proven in the widget
    COUNTERPARTY_VASP_NOT_FOUND --> AWAITING_COUNTERPARTY: action resend
    COUNTERPARTY_VASP_NOT_REACHABLE --> AWAITING_COUNTERPARTY: action resend
    COMPLETED --> FINISHED: payment_txn_id reported or deposit already settled
    FINISHED --> [*]
    EXPIRED --> [*]
```

### Entrega y reintentos

Didit envía cada mensaje que una transferencia debe enviar al margen de la solicitud que lo originó, y lo reintenta hasta que la otra parte lo acepta.
El objeto de transferencia que devuelven [Finalizar, cancelar o reenviar](https://docs.didit.me/es/management-api/travel-rule/update-transfer.md), [Confirmar la propiedad](https://docs.didit.me/es/management-api/travel-rule/confirm-ownership.md) y el [registro sunrise](#registro-sunrise-posterior-al-depósito) incluye el estado de entrega más reciente en `delivery`, al igual que el objeto `travel_rule` incrustado en la transacción; es `null` cuando la transferencia nunca debió ningún mensaje.

| Campo | Significado |
| - | - |
| `kind` | `SEND` (el primer mensaje a la contraparte), `ANSWER` (tu aceptación o rechazo, que debe enviarse a la red que lo solicitó), `TXID` (el hash on-chain, después de finalizar la transferencia), `CANCEL` (después de cancelarla) o `POLL` (una consulta de estado a una red que la ofrece, cada 5 minutos mientras la transferencia espera a la contraparte). |
| `status` | `QUEUED`, `SENDING`, `RETRYING`, `DELIVERED` o `FAILED`. |
| `rail` | El canal que transporta el mensaje; vacío hasta que Didit elige uno para un primer mensaje. |
| `attempts` | Intentos realizados hasta el momento. |
| `last_error` | Por qué falló el último intento; vacío si no falló ninguno. Un motivo breve que indica el paso y el tipo de fallo, por ejemplo `sygna permission request failed: HTTP 503` o `sygna status query failed: no answer in time`; cuando GTR responde con un error, se incluyen su propio código de estado y su mensaje. Los cuerpos de respuesta nunca se incluyen. |
| `next_attempt_at` | Cuándo se ejecuta el siguiente intento, mientras el mensaje está en `QUEUED` o `RETRYING`. |
| `delivered_at` | Cuándo la otra parte aceptó el mensaje. |

Un fallo del que la red todavía puede recuperarse (sin respuesta a tiempo, una conexión fallida, HTTP `408`, `429` o `5xx`) se reintenta al cabo de 30 segundos, 2 minutos, 10 minutos, 30 minutos y 1 hora.
Cuando un primer mensaje falla definitivamente (la red lo rechazó o el sexto intento también falló), la transferencia pasa a `COUNTERPARTY_VASP_NOT_REACHABLE` con `last_error` en su `timeline`, y puedes reintentarla con `action: "resend"`.
Cualquier otro mensaje que falle definitivamente queda anotado en el `timeline`.
`delivery` nunca sustituye al `status` de la transferencia: consulta el intercambio en `status` y usa `delivery` para ver por qué una transferencia sigue en espera.

### Valores de estado heredados

Si ya enviabas `travel_rule_details.status` antes de esta versión, esos valores siguen funcionando y se asignan automáticamente.
También se aceptan las grafías en camelCase de cualquier estado (por ejemplo, `counterpartyVaspNotFound`), tanto en el envío como en los valores de condición de las [reglas](https://docs.didit.me/es/transaction-monitoring/rules.md), y se normalizan a la forma canónica:

| Valor heredado | Se asigna a |
| - | - |
| `UNKNOWN` | `NOT_APPLICABLE` |
| `COMPLIANT` | `COMPLETED` |
| `PENDING_ACTION` | `ON_HOLD` |
| `PENDING_COUNTERPARTY` | `AWAITING_COUNTERPARTY` |
| `FAILED` | `CANCELLED` |
| `EXEMPT` | `NOT_APPLICABLE` |

## Configuración

Configura tu perfil de VASP y tu política de negociación una sola vez por aplicación con `GET`/`PUT /v3/travel-rule/settings/`.

```bash theme={null}
curl -X GET https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY"
```

```json theme={null}
{
  "is_enabled": false,
  "jurisdiction": "EU",
  "name_matching_strictness": "DEFAULT",
  "confirmation_timeout_hours": 48,
  "timeout_outcome": "HOLD",
  "threshold_amount": "0.00",
  "inbound_auto_accept": true,
  "allow_self_declaration": true,
  "allow_screenshot_proof": true,
  "auto_wallet_verification": true,
  "vasp_attribution_enabled": true,
  "counterparty_screening_enabled": false,
  "sunrise_policy": "",
  "sunrise_jurisdictions": ["CO", "KH", "VN"],
  "non_responsive_policy": "",
  "legal_name": "",
  "lei": "",
  "compliance_email": "",
  "is_discoverable": true,
  "travel_address": "",
  "disabled_networks": [],
  "networks": {
    "gtr": { "rail": "GTR", "mode": "unavailable", "platform_available": false, "connected": false },
    "trust": { "rail": "TRUST", "mode": "unavailable", "platform_available": false, "connected": false },
    "verifyvasp": { "rail": "VERIFYVASP", "mode": "unavailable", "platform_available": false, "connected": false },
    "sygna": { "rail": "SYGNA", "mode": "unavailable", "platform_available": false, "connected": false }
  }
}
```

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "is_enabled": true,
    "legal_name": "Origin CASP SL",
    "jurisdiction": "EU",
    "name_matching_strictness": "DEFAULT",
    "confirmation_timeout_hours": 48,
    "timeout_outcome": "HOLD",
    "is_discoverable": true
  }'
```

`PUT` es una actualización parcial: envía solo los campos que quieras cambiar.

| Campo | Tipo | Descripción |
| - | - | - |
| `is_enabled` | boolean | Activa el flujo de negociación gestionado para las transacciones `travelRule` salientes de esta aplicación. Requiere un `legal_name` no vacío (ya guardado o incluido en la misma solicitud); de lo contrario, la solicitud devuelve `400`. |
| `legal_name` | string | La razón social de tu VASP. Se muestra a la contraparte en la página de recogida por correo electrónico y se devuelve en el [directorio de VASP](#directorio). |
| `lei` | string | Tu Legal Entity Identifier, que se devuelve en el directorio de VASP. |
| `jurisdiction` | string | El código de la jurisdicción en la que opera tu VASP, de hasta 8 caracteres (por defecto, `"EU"`). |
| `name_matching_strictness` | string | `NONE`, `STRICT`, `CONTAINS`, `DEFAULT` o `FUZZY`; consulta más abajo. |
| `confirmation_timeout_hours` | integer | Horas que una transferencia en `AWAITING_COUNTERPARTY` puede permanecer en ese estado antes de expirar automáticamente. Mínimo `1`, por defecto `48`. |
| `timeout_outcome` | string | Qué ocurre con la transacción subyacente cuando una transferencia expira: `HOLD` la pasa a revisión, `REJECT` la rechaza y `PROCEED` deja su estado sin cambios. Por defecto, `HOLD`. `sunrise_policy` y `non_responsive_policy` tienen prioridad cuando alguna de ellas aplica. |
| `sunrise_policy` | string | `HOLD`, `REJECT`, `PROCEED` o `""` (por defecto) para seguir `timeout_outcome`: qué hace una transferencia expirada cuando su contraparte es una entrada del directorio en una jurisdicción incluida en `sunrise_jurisdictions`. Consulta [Políticas de sunrise y de contrapartes sin respuesta](#políticas-de-periodo-de-transición-y-de-falta-de-respuesta). |
| `non_responsive_policy` | string | `HOLD`, `REJECT`, `PROCEED` o `""` (por defecto) para seguir `timeout_outcome`: qué hace una transferencia expirada cuando su contraparte es una entrada del directorio cuya [capacidad de respuesta](#capacidad-de-respuesta) es `UNRESPONSIVE`. `sunrise_policy` se aplica primero cuando ambas encajan. |
| `sunrise_jurisdictions` | string\[] | Solo lectura. Los países que Didit considera en un periodo de sunrise de la Travel Rule, actualmente `["CO", "KH", "VN"]`. Cualquier otra jurisdicción sigue `timeout_outcome`. |
| `compliance_email` | string | Correo electrónico de contacto de cumplimiento para tu perfil de VASP. La [red de Didit](#la-red-de-didit) solo incluye tu perfil una vez que esta dirección se confirma mediante un enlace enviado por correo electrónico; cambiarla requiere una nueva confirmación. |
| `is_discoverable` | boolean | Indica si tu perfil de VASP puede figurar en la [red de Didit](#la-red-de-didit): otros clientes de Didit lo encuentran en `GET /v3/travel-rule/vasps/` y pueden contactarte a través del rail INTERNAL. Figurar en la red tiene condiciones adicionales; `didit_network` en la configuración indica cuáles faltan. Por defecto, `true`. |
| `inbound_auto_accept` | boolean | Cuando es `true`, una consulta `TRP` entrante cuya wallet beneficiaria es una entrada verificada de tu libreta de direcciones y cuyo nombre coincide se aprueba automáticamente. Cuando es `false`, queda en `ON_HOLD` a la espera de tu decisión. Las demás vías entrantes no leen esta configuración. Por defecto, `true`. |
| `allow_self_declaration` | boolean | Cuando es `true`, el [widget de propiedad de wallets](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) ofrece la autodeclaración como método de prueba, y puedes crear entradas en la [libreta de direcciones de wallets](#libreta-de-direcciones-de-wallets) con `self_declared: true`. Por defecto, `true`. |
| `allow_screenshot_proof` | boolean | Cuando es `true`, el [widget de propiedad de wallets](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) ofrece la carga de una captura de pantalla como método de evidencia de propiedad. Una captura de pantalla nunca verifica la wallet por sí sola: tu equipo de cumplimiento la revisa y confirma la transferencia. Es más débil que la firma criptográfica; desactívala cuando tu política exija una prueba de nivel de firma. Por defecto, `true`. |
| `auto_wallet_verification` | boolean | Cuando es `true`, una transferencia saliente que necesita que el usuario final demuestre el control de la wallet genera automáticamente una sesión del [widget de propiedad de wallets](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) vinculada a la transacción y la muestra en el bloque `action_required` de la transacción; los SDK de Didit la abren automáticamente en el [envío desde el cliente](https://docs.didit.me/es/transaction-monitoring/sdk-transaction-submission.md). Por defecto, `true`. |
| `counterparty_screening_enabled` | boolean | [Análisis de VASP contrapartes](#análisis-de-la-contraparte) opcional de sanciones y medios adversos, facturado por análisis al precio del Análisis AML de empresas. Cuando es `true`, Didit analiza la contraparte a la que llega un intercambio saliente cuando el intercambio comienza, y reutiliza un análisis de menos de 30 días de antigüedad. Por defecto, `false`: no se analiza ni se factura nada. |
| `vasp_attribution_enabled` | boolean | Cuando es `true`, una transferencia saliente que ningún rail puede enrutar se atribuye mediante [análisis de blockchain](#atribución-mediante-análisis-de-blockchain): la wallet de destino se asocia al VASP que la posee, la entidad se añade al directorio y los rails se vuelven a ejecutar una vez con el nombre atribuido. Por defecto, `true`. |
| `threshold_amount` | string (decimal) | Importe mínimo de transferencia que activa un intercambio gestionado, en la moneda predeterminada de tu aplicación: Didit lo compara con el importe de la transferencia convertido a esa moneda (o con el `amount_in_default_currency` que envíes), no con el importe en la moneda propia de la transferencia. Las transferencias por debajo de este importe se resuelven directamente como `NOT_APPLICABLE` y nunca se negocian. Si Didit no puede convertir el importe, el umbral no se aplica y la transferencia se intercambia. Las aplicaciones de sandbox no convierten importes, así que en ellas el umbral solo se aplica cuando envías `amount_in_default_currency`. Por defecto, `0.00`, en línea con el planteamiento del EU TFR sin importe mínimo, de modo que se comprueba cada transferencia independientemente de su tamaño. |
| `ownership_validation_mode` | string | `FULL`, `SIMPLIFIED` o `AUTOMATED`: cuánta prueba requiere la propiedad de una wallet. Consulta [Modos de validación de propiedad](#modos-de-validación-de-la-propiedad). Por defecto, `AUTOMATED`. |
| `simplified_validation_threshold` | string (decimal) | En el modo `SIMPLIFIED`, una transferencia por debajo de este importe acepta una autodeclaración. Por defecto, `0.00`. |
| `data_sharing_fields` | object | Los campos que envías sobre tus propios usuarios, por tipo de entidad. Consulta [Intercambio de datos](#compartición-de-datos). |
| `matching_rules` | object | Con qué rigor se compara cada campo de los datos de la contraparte, por tipo de entidad. Consulta [Coincidencia por campo](#coincidencia-por-campo). |
| `disabled_networks` | string\[] | Redes (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) por las que tus transferencias NO deben enrutarse a través de la membresía de plataforma de Didit. Esta lista nunca afecta a una red en la que hayas conectado tu propia membresía (Marketplace de la consola). Didit todavía no tiene ninguna membresía de plataforma, así que hoy la lista no tiene efecto en el enrutamiento (una red incluida en la lista indica `mode: off`). Valor predeterminado: `[]`. |
| `networks` | object | Solo lectura. Estado por red, con las claves `gtr` / `trust` / `verifyvasp` / `sygna`: `{rail, mode, platform_available, connected}`, donde `mode` es `own` (tu membresía conectada), `didit` (la membresía de plataforma de Didit, que todavía no está disponible en ninguna red), `off` (desactivada por ti) o `unavailable`. |
| `travel_address` | string | Solo lectura. La travel address de tu propio VASP: el endpoint `TRP` de consultas entrantes, codificado, que otros VASP usan para contactarte. Se rellena en cuanto se activa Travel Rule, por ejemplo `ta2ih1MicegQ3JqiKz9xT89KsSuwaDJYw8DgzmeS5uNDp3dGW3bweBWLKws442chRsyNxmmJnyWc7frxjjSeABVsYR11UuBePkw6E`. |

### Rigor de la coincidencia de nombres

| Valor | Comportamiento |
| - | - |
| `NONE` | Se acepta cualquier nombre de beneficiario y no se hace ninguna comparación. |
| `STRICT` | Los conjuntos de tokens normalizados de ambos nombres deben ser exactamente iguales. |
| `CONTAINS` | Todas las palabras de un nombre aparecen en el otro, por pocas que sean. |
| `DEFAULT` | Cada token del nombre más corto debe aparecer en el nombre más largo (coincidencia de subconjunto), y el nombre más corto necesita al menos dos tokens, salvo que ambos nombres sean idénticos. |
| `FUZZY` | La proporción de similitud entre las cadenas completas normalizadas debe ser de al menos `0.85`. |

### Modos de validación de la propiedad

`ownership_validation_mode` decide cuánta prueba requiere la propiedad de una wallet antes de que una transferencia se base en ella:

| Modo | Comportamiento |
| - | - |
| `FULL` | Siempre se requiere una prueba: un mensaje firmado, un depósito de prueba o una captura de pantalla revisada. La palabra del usuario final nunca cuenta. El widget no ofrece `SELF_DECLARATION`, iniciar una responde `403` y una entrada de la libreta de direcciones creada con `self_declared: true` responde `400`. |
| `SIMPLIFIED` | Se acepta una autodeclaración mientras la transferencia esté por debajo de `simplified_validation_threshold`; por encima, se requiere una prueba. Una transferencia entrante (una consulta TRP, un mensaje de red o un depósito que informas) se evalúa por su importe convertido a la moneda predeterminada de tu aplicación al tipo de cambio vigente. Un activo sin tipo de cambio, y cualquier transferencia de una aplicación de sandbox, cuenta como por encima del umbral. |
| `AUTOMATED` | La libreta de direcciones y las pruebas anteriores del usuario final responden por sí solas, autodeclaraciones incluidas mientras `allow_self_declaration` sea `true`. Es el modo predeterminado y el comportamiento que tenían todas las aplicaciones antes de que existieran los modos. |

Una wallet queda registrada por usuario final una vez verificada.
En `FULL` y `SIMPLIFIED`, una transferencia posterior solo la reutiliza cuando la respalda una prueba que el modo acepta para esa transferencia.
Cuando `inbound_auto_accept` no encuentra ninguna wallet de la libreta de direcciones con la que coincidir, una wallet cripto que hayas registrado en las transacciones de exactamente un usuario final identifica al titular.
Didit añade esa wallet a la libreta de direcciones del usuario final como tu autodeclaración, verificada salvo que el modo sea `FULL`. Nunca añade una wallet que la libreta de direcciones ya incluya con otro nombre de la misma cadena (`eth` y `ethereum`), incluida una registrada como de otro VASP.
Las comprobaciones de dirección que otros VASP hacen antes de enviar (a través de `GTR`, `Sygna` y `VerifyVASP`) también siguen el modo: con `FULL`, una wallet que el usuario final solo ha declarado no se informa como tuya.

### Compartición de datos

`data_sharing_fields` elige qué campos envía Didit a la contraparte sobre tus propios usuarios, por separado para personas físicas y empresas:

```json theme={null}
{
  "data_sharing_fields": {
    "individual": ["name", "wallet_address", "address", "date_of_birth"],
    "company": ["name", "wallet_address", "address"]
  }
}
```

* Las personas físicas pueden compartir `name`, `wallet_address`, `address`, `national_id`, `customer_identification`, `date_of_birth` y `place_of_birth`. Las empresas usan los cinco primeros.
* `name` y `wallet_address` se envían siempre.
* Un tipo de entidad para el que nunca hayas elegido comparte todos los campos. Una lista vacía también es una elección: comparte solo el nombre y la wallet.
* Un `PUT` fusiona por tipo de entidad, así que enviar `individual` deja intacta la elección guardada para `company`.
* Una elección que no puede cumplir las obligaciones del ordenante del régimen de tu `jurisdiction` (EU TFR o la Recomendación 16 del GAFI), incluida una lista vacía, se rechaza con `400`. Los errores aparecen bajo `data_sharing_fields`, con el tipo de entidad como clave.

### Coincidencia por campo

`matching_rules` define con qué rigor se compara cada campo de los datos de la contraparte con los que tienes:

```json theme={null}
{
  "matching_rules": {
    "individual": { "name": "DEFAULT", "date_of_birth": "STRICT", "address": "NONE", "account": "STRICT" },
    "company": { "name": "FUZZY", "address": "NONE", "account": "STRICT" }
  }
}
```

Cada valor es `NONE`, `STRICT`, `CONTAINS`, `DEFAULT` o `FUZZY`.
Valores predeterminados: `name` sigue a `name_matching_strictness`, `date_of_birth` y `address` son `NONE`, y `account` es `STRICT`.
Un campo que se omite conserva su valor predeterminado, y un campo que el tipo de entidad no compara (una empresa no tiene `date_of_birth`) se rechaza con `400`.

### Umbrales por jurisdicción

`threshold_amount` existe porque el alcance de Travel Rule varía según el regulador.
Didit usa por defecto `0.00` (la postura de la UE), de modo que se intercambian datos en todas las transferencias salvo que lo subas de forma deliberada:

| Régimen | Umbral | Notas |
| - | - | - |
| **UE**: Reglamento de transferencias de fondos (UE) 2023/1113 | **Sin mínimo** | Toda transferencia cripto entre CASP está incluida. La propiedad de una wallet sin custodia debe verificarse en transferencias superiores a 1.000 EUR. |
| **Recomendación 16 del GAFI** (referencia global) | 1.000 USD/EUR | Por debajo, el GAFI permite un conjunto de datos reducido (nombres y direcciones de wallet, sin verificación). |
| **Estados Unidos**: Travel Rule de la BSA | 3.000 USD | El umbral de transferencia de fondos que FinCEN aplica desde hace años, aplicado a la moneda virtual convertible. |
| **Reino Unido** | Equivalente a 1.000 EUR | Información completa por encima; conjunto de datos reducido por debajo (MLRs, parte 7A). |
| **Singapur**: MAS PSN02 | 1.500 SGD | Requisitos reducidos por debajo del umbral. |
| **Suiza**: FINMA | Sin mínimo | Se requiere información en todas las transferencias; se espera prueba de propiedad en las wallets sin custodia. |

Configura `threshold_amount` con la cifra de tu regulador; las transferencias por debajo se resuelven como `NOT_APPLICABLE` sin intercambiar ningún dato de identidad.
Los umbrales cambian: confirma la cifra vigente con tu asesor de cumplimiento en lugar de tomar esta tabla como asesoramiento legal.

### Modelo de datos IVMS 101

El estándar del sector para los datos que se intercambian en virtud de la Travel Rule es **IVMS 101** (interVASP Messaging Standard).
`travel_rule_details.originator_data` y `travel_rule_details.beneficiary_data` son payloads de persona al estilo IVMS 101: Didit los envuelve en el sobre nativo de cada canal (el canal TRP intercambia bloques `IVMS101` (`ivms101.2023`, indicado en el campo `ivms_version` de la transferencia), el canal Sygna su variante de IVMS cifrada con ECIES y los canales `GTR`, `TRUST` y `VERIFYVASP` sus propios sobres cifrados), de modo que una sola forma de payload llega a cada contraparte en el formato que espera su protocolo.

Didit lee estas claves de cada payload de persona cuando construye el mensaje IVMS 101: `first_name` y `last_name` (o un único `name` o `full_name`), `date_of_birth`, `place_of_birth`, `residence_country` (o `country`), `vendor_data` (o `customer_identification`) y `wallet_address`.

Dos reglas prácticas:

* **Alfabeto latino.** IVMS 101 exige valores en alfabeto latino; translitera los nombres que se escriben originalmente en otro sistema de escritura. La [coincidencia de nombres](#rigor-de-la-coincidencia-de-nombres) de Didit compara conjuntos de tokens normalizados, así que las diferencias de orden y de mayúsculas no hacen fallar un intercambio, pero sí lo harán sistemas de escritura distintos en cada lado.
* **Envía datos que hayas verificado.** Cuando el sujeto detrás de `vendor_data` es un usuario con una verificación KYC de Didit aprobada, Didit transmite la identidad verificada, no los valores que escribiste: consulta [Datos verificados y procedencia](#datos-verificados-y-procedencia).
  Para cualquier otro sujeto, Didit transmite exactamente los `originator_data` que envías, así que constrúyelos a partir de la identidad que verificaste en el onboarding, no de un campo de formulario sin verificar.
  Eso es lo que exige la formulación del GAFI de "información **exacta** y requerida del ordenante".
  En el canal `INTERNAL`, la aplicación del beneficiario también recibe el `subject` que enviaste (nombre, `vendor_data`, fecha de nacimiento, país y dirección) como la parte contraparte de su transacción entrante.

#### Datos verificados y procedencia

Cuando el sujeto de una transferencia es uno de tus usuarios, una persona física con una verificación KYC aprobada, Didit construye ese lado del intercambio a partir de los datos verificados:

* el ordenante de una transferencia saliente que creas con `POST /v3/transactions/`;
* el beneficiario de una transferencia entrante que notificas con `POST /v3/transactions/`, o con `POST /v3/travel-rule/inbound/` cuando el `holder_vendor_data` de la wallet coincidente identifica a ese usuario.

En `POST /v3/transactions/`, ambos casos se aplican a una transacción cuyo `transaction_category` es `travel_rule` mientras la Travel Rule está activada.

Los nombres verificados, la fecha y el lugar de nacimiento, el número y el tipo de documento, la dirección y el país de residencia (obtenido de esa dirección) prevalecen sobre los valores que enviaste. Un campo que la verificación no contiene conserva tu valor, al igual que una dirección completa que enviaste cuando la verificada no está lo bastante completa para transmitirse.

Los `metadata` de la transferencia, en el objeto `travel_rule` incrustado en la transacción, registran de dónde procede cada campo y dónde difieren tus valores:

```json theme={null}
{
  "metadata": {
    "originator_provenance": { "name": "verified", "date_of_birth": "verified", "customer_identification": "caller" },
    "originator_verified_differences": {
      "name": { "caller": "Jane Doe", "verified": "Jane Elizabeth Doe" }
    }
  }
}
```

`*_provenance` asigna a cada campo `verified` o `caller`, y `*_verified_differences` enumera cada campo en el que enviaste un valor distinto del verificado, sin tener en cuenta mayúsculas, espacios ni códigos de país de dos o tres letras. Mientras los datos de una transferencia entrante están [enmascarados](#datos-de-la-contraparte-enmascarados), las diferencias se omiten. Didit calcula ambos, por lo que se descartan las copias de estas claves, o de `name_match`, que envíes en `travel_rule_details.metadata`.

#### Enviar IVMS 101 directamente

Además de los objetos planos `originator_data` y `beneficiary_data`, `travel_rule_details` (en `POST /v3/transactions/`) y `POST /v3/travel-rule/inbound/` aceptan IVMS 101 auténtico:

* un bloque `originator` y un bloque `beneficiary`, con `originatorPersons` o `beneficiaryPersons` que contienen un `naturalPerson` o un `legalPerson`, y `accountNumber`;
* los mismos bloques dentro de un objeto `ivms101` (o `IVMS101`);
* una persona IVMS 101, o un bloque completo, como `originator_data` o `beneficiary_data`.

Cada lado admite una persona: un `naturalPerson`, o un `legalPerson`, que convierte a la parte en una empresa. Un `originator_data` o `beneficiary_data` plano no vacío prevalece sobre un bloque para el mismo lado.

```json theme={null}
{
  "travel_rule_details": {
    "status": "AWAITING_COUNTERPARTY",
    "beneficiary": {
      "beneficiaryPersons": [
        {
          "naturalPerson": {
            "name": { "nameIdentifier": [{ "primaryIdentifier": "Ruiz", "secondaryIdentifier": "Carlos", "nameIdentifierType": "LEGL" }] }
          }
        }
      ],
      "accountNumber": ["0xBeneficiaryWallet01"]
    }
  }
}
```

Un bloque mal formado responde `400` con la clave de su ruta, por ejemplo `{"travel_rule_details": {"originator.originatorPersons": ["must be a non-empty list of originator persons."]}}`. En `POST /v3/travel-rule/inbound/` las mismas claves están en el nivel superior, bajo `ivms101.` cuando usaste el envoltorio.

#### Datos requeridos por régimen

Mientras la Travel Rule está activada, una transferencia saliente igual o superior a tu umbral debe incluir lo que exige su régimen; de lo contrario, responde `400`. Solo se comprueban los lados que enviaste, los datos verificados cuentan para el ordenante y los errores aparecen bajo `travel_rule_details.originator_data` o `travel_rule_details.beneficiary_data`, por ejemplo `"EU TFR requires the originator name."` o `"FATF Recommendation 16 requires the beneficiary wallet address."`:

| Régimen | Ordenante | Beneficiario |
| - | - | - |
| EU TFR (tu `jurisdiction` es un estado miembro de la UE, Islandia, Liechtenstein, Noruega, `EU` o `EEA`; `EU` es el valor predeterminado) | El nombre, más la dirección, el número de documento oficial y el número de identificación del cliente juntos, o la fecha y el lugar de nacimiento. Una empresa no tiene la alternativa del nacimiento. | Nombre y dirección de la wallet |
| Recomendación 16 del GAFI (cualquier otra jurisdicción, incluida una en blanco) | El nombre, más uno de estos: la dirección, el número de documento oficial o el número de identificación del cliente, o la fecha y el lugar de nacimiento juntos. Una empresa no tiene la alternativa del nacimiento. | Nombre y dirección de la wallet |

Para el ordenante, la comprobación lee los campos que tu aplicación comparte en [`data_sharing_fields`](#compartición-de-datos), porque son todo lo que envía un canal; el beneficiario se comprueba tal como lo enviaste. Cuando la transferencia cumple el régimen solo con un campo que no compartes, el `400` indica el requisito del régimen y, a continuación, los campos que comparte tu configuración.

El número de documento oficial es `national_id` (o `document_number`), el número de identificación del cliente es `customer_identification` (o `vendor_data`) y la fecha de nacimiento es `date_of_birth`. Un `beneficiary_data.wallet_address` vacío se rellena a partir de `counterparty.payment_method.account_id` antes de la comprobación, y un retiro UTXO cuya salida del beneficiario Didit infirió de `travel_rule_details.utxo` cuenta como si la incluyera. Una transferencia Lightning a la que no se aplica la Travel Rule no se comprueba.

### Direcciones de viaje

Una **dirección de viaje** (travel address) es una cadena compacta y codificada que apunta al endpoint de consultas entrantes `TRP` de un VASP. Nunca expone una URL en bruto ni ninguna dirección de wallet.
Una vez activado Travel Rule, Didit genera tu propia `travel_address` (que se devuelve como solo lectura en la configuración) para que puedas compartirla con otros VASP que te contacten por el canal `TRP`.
Cada una de las wallets de tu propia libreta de direcciones recibe además una `receiving_travel_address` propia: una consulta enviada a ella identifica esa wallet, de modo que Didit no tiene que buscarla por número de cuenta ni por nombre del titular.
El host TRP público de Didit todavía no responde a otros VASP, así que la recepción por `TRP` no estará disponible hasta que lo haga: consulta [Redes de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md).
Cuando conozcas la dirección de viaje de una contraparte, guárdala en la [entrada de la libreta de direcciones de wallets](#libreta-de-direcciones-de-wallets) de destino para que Didit envíe las transferencias de ese beneficiario directamente por `TRP` en lugar de recurrir al correo electrónico.
Didit valida las direcciones de viaje que guardas en una entrada de la libreta de direcciones de wallets o que envías en `originating_vasp`: cada una debe empezar por `ta` y decodificarse en una URL de consulta que incluya `t=i`, por lo que un valor de ejemplo como `ta...` devuelve `400`.
Una `beneficiary_data.travel_address` en una transacción no se valida: si no se puede decodificar, se omite el canal `TRP`.

La codificación es Base58Check con el prefijo `ta`: el host y la ruta del endpoint (que siempre incluye el par de consulta `t=i`), más una suma de verificación de cuatro bytes con doble SHA-256, todo codificado en base58.
Por eso una dirección real tiene este aspecto y ronda los 100 caracteres:

```text theme={null}
ta2ih1MicegQ3JqiKz9xT89KsSuwaDJYw8DgzmeSEp1h9tduJcNDZ5SgKLEHeyGMcS1s2HgbM6undFrMQknhM5aTXw3G9KBzi16hx
```

Donde Didit valida una dirección de viaje, un valor que no sea una dirección bien formada y con una suma de verificación válida devuelve `400` con `"Invalid travel address."`.
Toma una dirección real de la respuesta de tu propia configuración o pídesela directamente a la contraparte.

## Pruebas sin credenciales de red

No necesitas ser miembro de GTR, TRUST, VerifyVASP ni Sygna para probar las rutas que no requieren membresía. Sí necesitas una clave de API de Didit para la aplicación que estás probando.

* **Salida en sandbox:** envía una transacción `travelRule` desde una aplicación de sandbox. Tras las comprobaciones de umbral y de wallet sin custodia, el [Didit Test VASP](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) responde a la transacción dentro de Didit con el escenario que elijas según la wallet o el nombre del beneficiario: aceptación, rechazo, nombre no coincidente, no localizable, tiempo de espera agotado o wallet sin custodia. Ninguna red, correo electrónico ni otro cliente de Didit recibe nada.
* **Entrada en sandbox:** haz que el VASP de prueba te envíe una transferencia con [Disparar una transferencia entrante del VASP de prueba](https://docs.didit.me/es/management-api/travel-rule/trigger-test-vasp-inbound.md), o registra una tú mismo con [Registrar una transferencia entrante de Travel Rule](https://docs.didit.me/es/management-api/travel-rule/register-inbound.md). Prueba una wallet desconocida, una wallet no verificada, un nombre de beneficiario que no coincide y una wallet verificada que sí coincide. Así se ejercitan decisiones reales de entrada sin contactar con ninguna red.
* **Dos aplicaciones de producción controladas:** usa el canal `INTERNAL` entre dos de tus propias aplicaciones de producción (la receptora es localizable y demuestra el control de la wallet de destino con un mensaje firmado o un depósito de prueba), o una contraparte TRP controlada, para probar un intercambio entre dos partes sin credenciales de una red comercial. Las aplicaciones de producción pueden generar cargos y notificaciones habituales; usa identidades de prueba y contrapartes que controles.

Consulta [Probar Travel Rule en sandbox](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) para ver todos los escenarios y su resultado exacto. Las pruebas exitosas en sandbox o las pruebas de protocolo locales no validan las credenciales, la membresía ni la interoperabilidad en producción de una red comercial. Para ello se necesita un sandbox autorizado de la red o un intercambio controlado en producción con credenciales de membresía válidas.

## Enviar una transferencia

Incluye la transferencia en [`POST /v3/transactions/`](https://docs.didit.me/es/transaction-monitoring/transactions) estableciendo `transaction_category` en `travelRule` (o `travel_rule`) y adjuntando un objeto `travel_rule_details` (alias: `travelRule`).

El bloque `travel_rule_details` es opcional, pero en cuanto lo adjuntas, `travel_rule_details.status` es obligatorio: un bloque sin él devuelve `400`.
Cuando Travel Rule está **habilitado** para tu aplicación, Didit ignora el valor de `status` que envías y gestiona el intercambio por sí mismo:

1. Si el importe es inferior al `threshold_amount` que configuraste, la transferencia se resuelve de inmediato como `NOT_APPLICABLE` y no se negocia nada.
2. Si el método de pago de la contraparte declara el destino como una wallet sin custodia (`payment_method.method_type: "unhosted_wallet"`), no se prueba ningún canal: la transferencia pasa directamente a `UNCONFIRMED_OWNERSHIP` y el widget de propiedad de la wallet se genera automáticamente (consulta [Wallets sin custodia declaradas](#wallets-sin-custodia-declaradas)).
3. En caso contrario, los canales se ejecutan por orden de prioridad, y el primero que puede llegar a la contraparte lleva el intercambio:
   * `INTERNAL`: exactamente un cliente de Didit distinto tiene una prueba de mensaje firmado o de depósito de prueba para `beneficiary_data.wallet_address`, realizada después del último cambio de titular de la wallet. Tu propia aplicación nunca cuenta, y cuando tu usuario final eligió un miembro de la red de Didit en el [widget de propiedad de la wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md), solo cuenta la prueba de ese miembro. La aplicación de ese cliente está en producción (no en sandbox), tiene Travel Rule activado y `is_discoverable` establecido, y es el VASP que indicaste cuando envías `counterparty_vasp_lei` o `counterparty_vasp_name`. Una wallet que solo está autodeclarada, probada con una captura de pantalla, sin verificar o solo registrada en una libreta de direcciones nunca recibe nada a través de `INTERNAL`.
   * `TRP`: el activo de la transferencia tiene una correspondencia de Digital Token Identifier para la red de la transferencia (consulta [Identificadores de activos de TRP](#identificadores-de-activos-de-trp)), y el payload incluye `beneficiary_data.travel_address`, la propia entrada de libreta de direcciones del destino almacena uno, o la contraparte se resuelve en el [directorio](#directorio) (mediante `counterparty_vasp_lei` o `counterparty_vasp_name`) con un endpoint de TRP.
   * `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`: conectaste tu propia membresía para esa red en **Marketplace**, y la contraparte se resuelve en un id de red (campo explícito o entrada del directorio; consulta [Campos de resolución de la contraparte](#campos-de-resolución-de-la-contraparte)).
     Didit aún no tiene membresía de plataforma en estas redes (está en proceso de onboarding como proveedor), por lo que `disabled_networks` no modifica este paso por ahora.
   * `EMAIL`: se proporcionó `beneficiary_data.counterparty_vasp_email`, o `counterparty_vasp_name` se resuelve en una entrada del directorio con un correo electrónico de cumplimiento.
4. Si ningún canal puede resolver una contraparte, Didit ejecuta la cadena de [descubrimiento de la contraparte](#descubrimiento-de-la-contraparte). Con `vasp_attribution_enabled` activado, esto incluye la [atribución mediante análisis de blockchain](#atribución-mediante-análisis-de-blockchain): la wallet de destino se resuelve en el VASP al que pertenece, el nombre atribuido se escribe en `beneficiary_data.counterparty_vasp_name` (cuando está vacío) y en el [directorio](#directorio), y los canales se vuelven a ejecutar una vez; así, una wallet atribuida a un VASP cuya entrada del directorio incluye un endpoint de TRP, un id de red o un correo electrónico de cumplimiento se enruta en esta segunda pasada.
5. Si la contraparte sigue sin resolverse, la transferencia pasa a `COUNTERPARTY_VASP_NOT_FOUND`. En las transferencias salientes, Didit genera automáticamente el [widget de propiedad de la wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) (cuando `auto_wallet_verification` está activado) para que la transferencia aún pueda completarse como una transferencia a una wallet sin custodia, y puedes volver a ejecutar el enrutamiento más adelante con `action: "resend"` cuando tengas mejores datos de la contraparte.

Los pasos 1 y 2 ocurren dentro de la solicitud. Los pasos 3 a 5 se ejecutan justo después de la respuesta: la transferencia se devuelve como `AWAITING_COUNTERPARTY` con `protocol: null`, y cada resultado llega como un webhook [`travel_rule.status.updated`](#webhooks).

### Identificadores de activos de TRP

`TRP` identifica el activo transferido mediante su Digital Token Identifier (DTI) ISO 24165.
Un DTI identifica un token en una blockchain, por lo que un token multicadena tiene un DTI por red.

Didit envía transferencias a través de `TRP` para estos activos:

| Activo | Red | DTI |
| - | - | - |
| `BTC` | Bitcoin | `4H95J0R2X` |
| `ETH` | Ethereum | `X9J9K872S` |
| `USDC` | Ethereum | `CK9PW1MFH` |
| `USDC` | Celo | `2ZTG3NNVB` |
| `USDC` | Base | `CP6817N4B` |
| `USDC` | Optimism | `898NNTPZJ` |
| `USDC` | Arbitrum One | `4ZSZS1F4F` |
| `USDC` | Polygon PoS | `LS71LQK3L` |
| `USDC` | Avalanche C-Chain | `45J6XJX7H` |
| `USDC` | Solana | `5R3XFPZSM` |
| `USDC` | Plume | `N064ZKXDM` |

Los identificadores de `USDC` son los que el emisor del token publica en su white paper de MiCA.

Para un token multicadena, la transferencia debe indicar su red en `transaction_details.crypto_params.crypto_chain` (por ejemplo, `CELO`, `BASE`, `OP`, `ARB` o `POL`).
Sin una red, o en una red sin correspondencia, la transferencia no se envía a través de `TRP` y Didit prueba los canales restantes: primero las redes de interoperabilidad y después el correo electrónico.

`USDT` todavía no tiene correspondencia.
Un token sin correspondencia de DTI, como la stablecoin propia de una empresa, requiere que su emisor registre un DTI ante la autoridad de registro ISO 24165, uno por token y por blockchain.
Una vez que existan los DTI, contacta con el soporte de Didit indicando cada DTI, su blockchain y los decimales del token, y Didit añadirá la correspondencia.

Las consultas `TRP` entrantes que incluyen un DTI por cadena con correspondencia se registran con la moneda del token, el importe en los decimales del token y la red.

### Descubrimiento de la contraparte

Una transferencia que solo incluye una dirección de wallet llega igualmente a su contraparte siempre que alguien pueda identificarla.
Antes de declarar que una transferencia saliente no se puede enrutar, Didit consulta, en este orden, y se detiene en el primer paso que identifica un VASP con una ruta:

| Paso | Qué hace |
| - | - |
| `internal_address_book` | Otro cliente de Didit demostró el control de la wallet (una firma o un depósito de prueba), por lo que el canal `INTERNAL` le entrega la transferencia. Una entrada de libreta de direcciones no probada nunca cuenta. |
| `wallet_attribution` | La atribución de la wallet mediante análisis de blockchain, emparejada con un VASP del directorio que tenga una ruta. Un resultado almacenado se reutiliza y se cobra una sola vez. Requiere `vasp_attribution_enabled`. |
| `network_lookup` | Una red de Travel Rule que responde "quién tiene esta dirección", cuando tu aplicación tiene acceso a ella. Hoy solo GTR lo ofrece, y se ejecuta cuando envía el canal GTR. En caso contrario, el paso se registra como `skipped` con el motivo. |
| `customer_hint` | El nombre del VASP, el LEI o la jurisdicción que enviaste en `beneficiary_data`, emparejado con un VASP del directorio que tiene una ruta. A una `travel_address` o a un correo de cumplimiento se llega por su propio canal. |
| `end_user` | Nadie identificó a la contraparte, así que se le pregunta al usuario final. Consulta más abajo. |

El campo `discovery` de la transferencia enumera cada paso ejecutado con su `outcome` (`match`, `miss` o `skipped`), un `reason` legible por máquina, el `vasp` y el `rail` que encontró, y una marca de tiempo.
Un VASP elegido por ti o por el usuario final tiene prioridad sobre cualquier paso automático: el descubrimiento nunca lo sustituye por su propia suposición.

Cuando ningún paso identifica una contraparte, la transferencia pasa a `COUNTERPARTY_VASP_NOT_FOUND`, o a `COUNTERPARTY_VASP_NOT_REACHABLE` cuando se identificó un VASP pero ninguna de sus rutas está disponible para tu aplicación.
La transferencia lleva entonces un `reason` (`awaiting_end_user`, `no_directory_match`, `directory_match_no_route` o `picked_member_without_proven_wallet` cuando el miembro elegido por el usuario final no ha demostrado la titularidad de la wallet) y una lista de `next_actions`:

| `action` | Significado |
| - | - |
| `select_counterparty_vasp` | El usuario final elige el VASP de destino en el [widget de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md), o lo indicas tú mismo con `{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}` en el [endpoint de transferencia](#enviar-una-transferencia). La transferencia se enruta a ese VASP y se envía de nuevo. |
| `declare_self_hosted` | El usuario final declara en el mismo widget que la wallet es sin custodia. |
| `add_vasp_hint` | Envía un nombre de VASP, un LEI o una `travel_address` en `beneficiary_data` y vuelve a enviar. |
| `update_compliance_email` | Vuelve a indicar el correo de cumplimiento de la contraparte cuando el primero fue rechazado; consulta [Por qué una transferencia está bloqueada](#por-qué-una-transferencia-está-bloqueada). |
| `resend` | Vuelve a ejecutar el descubrimiento con lo que haya cambiado. |

El enlace del widget es `url` en las acciones que realiza el usuario final.
Cuando hay una acción de titularidad de wallet pendiente, el bloque `action_required` de la transacción (tipo `wallet_ownership`) lleva los mismos `reason` y `next_actions`, de modo que un cliente que ya sigue `action_required` muestra el selector sin trabajo adicional.

### Campos de resolución de la contraparte

Todo lo que Didit sabe sobre la contraparte procede de `travel_rule_details.beneficiary_data`.
Estos campos determinan la resolución del canal; todos son opcionales:

| Campo | Determina |
| - | - |
| `wallet_address` | La coincidencia en la libreta de direcciones de `INTERNAL`, la búsqueda en la libreta de direcciones de `TRP` y los flujos de titularidad de wallet. Si lo omites, Didit usa `counterparty.payment_method.account_id`. |
| `chain` | Acota ambas búsquedas en la libreta de direcciones: una entrada coincide solo cuando su `chain` es igual a este valor (sin distinguir mayúsculas de minúsculas) o cuando la entrada no tiene `chain`. Si lo omites, Didit lo rellena a partir de `transaction_details.crypto_params.crypto_chain`, de `custom_properties.crypto_chain` o de la moneda de la transferencia, en mayúsculas, pero solo cuando ese valor es una cadena que Didit reconoce (por ejemplo `ETH`, `BTC`, `SOL`, `TRX`); de lo contrario, la transferencia no lleva cadena y coincide con entradas de cualquier cadena. Para una transferencia en `USDT` o `USDC` sin cadena explícita, Didit la infiere a partir de un hash de transacción en `transaction_details.payment_reference_id` (un hash `0x` da `ETH`). |
| `memo` | La etiqueta de destino o el memo de `wallet_address` en una red con memo. Forma parte de la wallet allí donde se compara `wallet_address` (consulta [Redes con memo y etiqueta](#redes-con-memo-y-etiqueta)). Alias: `destinationTag`. |
| `travel_address` | Enruta directamente por `TRP`: la señal más fuerte que puedes pasar. |
| `counterparty_vasp_lei` | Búsqueda en el directorio por LEI para `TRP`, `GTR`, `TRUST`, `VERIFYVASP` y `SYGNA`. También se contrasta con la identidad que informa el endpoint TRP: una discrepancia, o una identidad sin LEI, aborta el intercambio como `COUNTERPARTY_VASP_NOT_REACHABLE`. |
| `counterparty_vasp_name` | Búsqueda en el directorio para `TRP`, `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA` y `EMAIL`: el nombre exacto, el mismo nombre escrito de otra forma (`B.V.` por `BV`, un acento) y, después, un alias de una entrada. Se contrasta de forma aproximada con la identidad TRP cuando ambos están presentes. |
| `counterparty_vasp_jurisdiction` | Código de país ISO 3166 de la entidad receptora cuando el VASP indicado es una marca con varias entidades reguladas, o cuando varias entradas del directorio comparten el nombre; consulta [Marcas y sus entidades](#marcas-y-sus-entidades). |
| `counterparty_gtr_vasp_code` | ID de red `GTR` explícito: omite el directorio. |
| `counterparty_trust_membership_id` | ID de red `TRUST` explícito: omite el directorio. |
| `counterparty_verifyvasp_id` | ID de red `VerifyVASP` explícito: omite el directorio. |
| `counterparty_sygna_vasp_code` | Código de VASP de `Sygna Bridge` explícito: omite el directorio. |
| `counterparty_vasp_email` | Contacto de cumplimiento explícito para el canal `EMAIL`: omite el directorio. |

### Estructuras de cadena

En una cadena de cuentas (cadenas EVM, Solana, Tron), una transferencia mueve fondos de una dirección a otra, y Didit lee ambas wallets directamente de la transacción.
Otras tres estructuras necesitan más, y lo que Didit resolvió para ellas figura en la transferencia como `chain_details` (vacío, `{}`, en una cadena de cuentas).
`chain_details.originator` y `chain_details.beneficiary` llevan cada uno la `address`, su `memo` y la `source` de la que procede, y la comparación y el enrutamiento leen primero las wallets de ahí.

#### Transferencias UTXO

Una transacción de Bitcoin, Litecoin, Bitcoin Cash o Dogecoin gasta entradas de cualquier número de direcciones y paga cualquier número de salidas, algunas de ellas cambio que vuelve al remitente.
Envía las entradas y salidas como `travel_rule_details.utxo` (importes en la unidad propia de la moneda, como cadenas de texto decimales), y Didit infiere lo que no declares:

* **Ordenante**: `originator_data.wallet_address` cuando lo envías; si no, la dirección de entrada que más aportó (`source: largest_input`).
* **Beneficiario**: la wallet declarada; si no, la única salida que no devuelve cambio a una dirección de entrada (`only_non_change_output`); si no, la única salida que paga el importe de la transferencia (`amount_match`).

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "btc-withdrawal-0042",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "amount": "0.25",
      "currency": "BTC",
      "currency_kind": "crypto"
    },
    "subject": { "vendor_data": "user-042", "full_name": "Ana Diaz" },
    "counterparty": { "full_name": "Luis Perez" },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "beneficiary_data": { "name": "Luis Perez", "counterparty_vasp_name": "Destination Exchange" },
      "utxo": {
        "inputs": [
          { "address": "bc1qsenderhotwallet01", "amount": "0.30" },
          { "address": "bc1qsendercoldwallet02", "amount": "0.05" }
        ],
        "outputs": [
          { "address": "bc1qbeneficiarydeposit01", "amount": "0.25" },
          { "address": "bc1qsenderhotwallet01", "amount": "0.0999" }
        ]
      }
    }
  }'
```

La transferencia incluye entonces:

```json theme={null}
{
  "chain_details": {
    "chain": "BTC",
    "shape": "utxo",
    "originator": { "address": "bc1qsenderhotwallet01", "memo": "", "source": "largest_input" },
    "beneficiary": { "address": "bc1qbeneficiarydeposit01", "memo": "", "source": "only_non_change_output" },
    "utxo": {
      "inputs": [
        { "address": "bc1qsenderhotwallet01", "amount": "0.300000000000000000" },
        { "address": "bc1qsendercoldwallet02", "amount": "0.050000000000000000" }
      ],
      "outputs": [
        { "address": "bc1qbeneficiarydeposit01", "amount": "0.250000000000000000" },
        { "address": "bc1qsenderhotwallet01", "amount": "0.099900000000000000" }
      ],
      "change_output_indexes": [1],
      "beneficiary_output_index": 0
    }
  }
}
```

`chain_details.warnings` señala lo que no cuadra: `declared_originator_not_an_input`, `declared_beneficiary_not_an_output`, `beneficiary_output_ambiguous` (no se pudo distinguir una única salida) y `beneficiary_output_amount_differs`.
`utxo` en cualquier otra cadena devuelve un `400`, y cada lista admite como máximo 1000 entradas.
Un depósito notificado usa el mismo objeto `utxo` (consulta [Registro sunrise tras el depósito](#registro-sunrise-posterior-al-depósito)).

#### Redes con memo y etiqueta

En XRP, Stellar (XLM), EOS, Cosmos (ATOM) y Hedera (HBAR), un exchange recibe a todos sus clientes en una única dirección compartida y los distingue por la etiqueta de destino o el memo.
Por eso el memo forma parte de la wallet: envíalo como `payment_method.memo` en el participante, o como `memo` en `originator_data` / `beneficiary_data` (alias `destinationTag`), y Didit compara la dirección y el memo de forma conjunta.

* Una entrada de la libreta de direcciones con memo solo coincide con las transferencias que indican ese memo. Una entrada sin memo coincide con toda la dirección. Una transferencia que no indica ningún memo nunca llega a una entrada que sí lo tiene: en una dirección compartida, un depósito sin su etiqueta no pertenece a nadie.
* Una X-address de XRP lleva la etiqueta dentro: Didit la separa en la dirección clásica y la etiqueta (`source: x_address`), de modo que una wallet registrada en cualquiera de los dos formatos coincide con una transferencia en el otro.
* Cada memo de una dirección compartida es un método de pago independiente en la transacción.
* Qué acepta cada red: una etiqueta de destino de XRP es un número entero de 0 a 4294967295 (se acepta un número JSON); un memo de Stellar es un texto de hasta 28 bytes, un id de 64 bits o un hash de 32 bytes en hexadecimal; EOS admite hasta 256 bytes, Cosmos hasta 256 caracteres y Hedera hasta 100 bytes. Un memo en una cadena que no los admite (Bitcoin, cadenas EVM, Solana, Tron, Litecoin, Bitcoin Cash, Dogecoin, Lightning) devuelve un `400`.

#### Lightning

Un pago Lightning no tiene una dirección on-chain del beneficiario: quien paga dispone de una solicitud de pago.
En una transferencia cripto de bitcoin o Lightning, `payment_method.account_id` puede ser esa solicitud, y Didit identifica al beneficiario a partir de ella sin contactar con ninguna red:

| Lo que envías | Beneficiario |
| - | - |
| Factura BOLT11 (`lnbc...`) | El nodo destinatario del pago, indicado en la factura o recuperado a partir de su firma. |
| Oferta o factura BOLT12 (`lno1...`, `lni1...`) | El nodo emisor, salvo que se oculte tras rutas cegadas (blinded paths). |
| Lightning Address (`name@domain`) | La propia dirección. |
| Id de nodo | El propio nodo. |
| LNURL (`lnurl1...`, `lnurlp://`) | Ninguno: identifica un servicio, no un destinatario del pago. |

El destinatario del pago se guarda como la cuenta y como `chain_details.beneficiary` (`source: invoice_payee`), en la cadena `LIGHTNING`, y el contenido de la solicitud está en `chain_details.lightning`.
Cuando la solicitud no indica ningún destinatario, una transferencia saliente queda en `NOT_APPLICABLE`, con el motivo en `chain_details.not_applicable_reason` y en su `timeline`: `LIGHTNING_NO_PAYEE_IDENTIFIER`, `LIGHTNING_BOLT12_BLINDED_PAYEE` o `LIGHTNING_LNURL_NAMES_NO_PAYEE`.
Un valor se interpreta como Lightning solo en bitcoin, en `LIGHTNING` o cuando no se indica ninguna cadena (una Lightning Address, solo en bitcoin o `LIGHTNING`): en cualquier otra cadena se trata como una dirección propia de esa cadena.

> [!NOTE]
>
> La vía `INTERNAL` solo llega a otro cliente de Didit a través de una wallet cuyo control ese cliente haya demostrado con un mensaje firmado o un depósito de prueba, y esas pruebas existen actualmente para Bitcoin, cadenas EVM, Solana y Tron.
> Por tanto, en redes con memo, Lightning, Litecoin, Bitcoin Cash y Dogecoin, una transferencia nunca llega a otro cliente de Didit a través de `INTERNAL`.
> La coincidencia por memo, etiqueta y Lightning sigue aplicándose a tu propia libreta de direcciones: transferencias entrantes, depósitos notificados y consultas `TRP` dirigidas a tus wallets.

### Actualizar la wallet del ordenante

Es habitual que un retiro se declare desde la wallet principal de tu cliente y se emita desde las direcciones que tuvieran los fondos.
Registra la wallet de la que realmente salieron los fondos con `PATCH /v3/transactions/{transaction_id}/travel-rule/`:

```bash theme={null}
curl -X PATCH "https://verification.didit.me/v3/transactions/$TRANSACTION_ID/travel-rule/" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "action": "update_originator_wallet", "wallet_address": "bc1qsendercoldwallet02" }'
```

* Solo para transferencias salientes, y nunca para una en estado `CANCELLED` o `EXPIRED` (`409`).
* Cuando se conocen las entradas UTXO de la transferencia, la wallet debe ser una de ellas (de lo contrario, `400`). En una red con memo, envía también `memo`.
* Solo modifica el registro: no se vuelve a enviar nada a la contraparte y el estado no cambia. `chain_details.originator` pasa a ser la nueva wallet con `source: updated`, el `timeline` registra la wallet anterior y la nueva, y la contrapartida `INTERNAL` de la transferencia se actualiza de la misma forma.

### Atribución mediante análisis de blockchain

Aunque solo indiques una dirección de wallet, Didit puede averiguar quién está al otro lado.
Si ninguna vía puede enrutar la transferencia, Didit resuelve la wallet de destino con los datos de atribución de análisis de blockchain: el mismo análisis que impulsa el [análisis de transacciones cripto](https://docs.didit.me/es/transaction-monitoring/aml-screening.md) sabe qué wallets pertenecen a qué exchanges y custodios.
La atribución solo se ejecuta en transferencias salientes que incluyen tanto una wallet de destino como un `chain` (consulta [Campos de resolución de la contraparte](#campos-de-resolución-de-la-contraparte)); sin cadena, se omite.

Cuando la wallet se atribuye a una entidad conocida, Didit:

1. Registra la atribución en la transferencia: se rellena `beneficiary_data.counterparty_vasp_name` (si no lo proporcionaste) y los metadatos de la transferencia incluyen un bloque `vasp_attribution` con el nombre de la entidad, el tipo de entidad, el país y `source: "blockchain_analytics"`.
2. Añade la entidad al [directorio de VASP](#directorio) (o la hace coincidir con la entrada existente), para que la atribución se mantenga estable entre transferencias.
3. Vuelve a ejecutar las vías una vez con el nombre atribuido: una entrada del directorio que ya tiene un endpoint TRP hace que la transferencia se enrute de inmediato en lugar de quedar en `COUNTERPARTY_VASP_NOT_FOUND`.

La llamada de atribución sirve también como un análisis cripto completo: la transacción recibe el resultado íntegro del análisis (puntuación de riesgo, categoría de riesgo de la wallet, instantánea de la red) exactamente como si se hubiera ejecutado la monitorización cripto, y el `custom_values.aml_screening_trigger` de la transacción se establece en `travel_rule_attribution` para que veas que el análisis se ejecutó porque el enrutamiento de la Travel Rule lo requería.
Cuando la monitorización cripto ya analizó la misma wallet en esta transacción, se reutiliza el resultado guardado: no hay una segunda llamada de análisis ni un segundo cargo.
La atribución nunca bloquea la creación de la transacción: si la consulta de análisis falla o tu saldo no alcanza para cubrirla, la transferencia simplemente pasa a `COUNTERPARTY_VASP_NOT_FOUND` y no se cobra nada por el intento.
Con `action: "resend"`, se reutiliza una atribución registrada anteriormente en lugar de volver a consultarla.

Desactiva todo el paso con `vasp_attribution_enabled: false` en la [configuración](#configuración).
Consulta [Precios](#precios) para saber cómo se factura la llamada de atribución.

Cuando Travel Rule está **desactivada**, `travel_rule_details` (incluido un `status` que proporcione quien hace la llamada, sea heredado o actual) se sigue registrando en la transacción, pero de forma pasiva: no se despacha por ningún canal.
Úsalo para completar con carácter retroactivo los datos de cumplimiento que ya registraste con tu propio proceso.
Una transferencia saliente pasiva no inicia ningún intercambio, por lo que se factura como Transaction Screening y no en la [línea de Travel Rule](#precios).

Con Travel Rule activada, esta solicitud se enruta por el canal `EMAIL`, porque indica el correo electrónico de cumplimiento de la contraparte y ningún canal anterior puede llegar al beneficiario:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "trv-2026-07-05-001",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "action_type": "transfer",
      "amount": "0.25",
      "currency": "ETH",
      "currency_kind": "crypto"
    },
    "subject": {
      "entity_type": "individual",
      "vendor_data": "user-042",
      "full_name": "Jane Doe"
    },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "originator_data": {
        "first_name": "Jane",
        "last_name": "Doe",
        "date_of_birth": "1990-04-12",
        "residence_country": "ES",
        "customer_identification": "user-042",
        "wallet_address": "0x135908330861442a814796ae99feac507925782a"
      },
      "beneficiary_data": {
        "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
        "name": "Ana Diaz",
        "counterparty_vasp_email": "compliance@bene-casp.example"
      }
    }
  }'
```

La respuesta, reducida a los campos que importan aquí:

```json theme={null}
{
  "uuid": "22222222-3333-4444-5555-666666666666",
  "txn_id": "trv-2026-07-05-001",
  "transaction_type": "travelRule",
  "direction": "OUTBOUND",
  "status": "APPROVED",
  "amount": "0.25",
  "currency": "ETH",
  "currency_type": "crypto",
  "travel_rule": {
    "uuid": "33333333-4444-5555-6666-777777777777",
    "status": "AWAITING_COUNTERPARTY",
    "protocol": null,
    "required": true,
    "obligations_count": 0,
    "originator_data": {
      "first_name": "Jane",
      "last_name": "Doe",
      "date_of_birth": "1990-04-12",
      "residence_country": "ES",
      "customer_identification": "user-042",
      "wallet_address": "0x135908330861442a814796ae99feac507925782a"
    },
    "beneficiary_data": {
      "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
      "name": "Ana Diaz",
      "counterparty_vasp_email": "compliance@bene-casp.example",
      "chain": "ETH"
    },
    "metadata": {
      "compliance_email_source": "caller_supplied"
    }
  },
  "action_required": null
}
```

* `originator_data` es lo que enviaste, porque el sujeto del ejemplo no tiene una verificación KYC aprobada; para un usuario verificado, Didit lo construye a partir de los datos verificados (consulta [Datos verificados y procedencia](#datos-verificados-y-procedencia)).
  El canal `EMAIL` muestra al destinatario solo los campos del ordenante que compartes en [`data_sharing_fields`](#compartición-de-datos).
* `beneficiary_data.chain` es `ETH` porque la solicitud no indicaba ninguna cadena, así que Didit la tomó de la moneda.
* `status` es `APPROVED` porque ninguna regla actuó sobre la transacción; tus propias reglas pueden establecer otro estado.
* El contacto de cumplimiento recibe el enlace de recogida, y la transferencia se completa, no supera la coincidencia de nombre o se rechaza cuando responde, o expira si no responde (consulta [Recogida por correo electrónico](#recogida-por-correo-electrónico-para-contrapartes-inalcanzables)).

`protocol` sigue siendo `null` porque el canal se elige después de la respuesta (por ejemplo, `EMAIL` cuando proporcionaste `counterparty_vasp_email`): [Obtener transacción](https://docs.didit.me/es/management-api/transactions/get.md) lo muestra una vez elegido, y cada webhook `travel_rule.status.updated` posterior lo incluye en `rail`.
Si la wallet beneficiaria pertenece a otro cliente de Didit que demostró tener su control, el canal `INTERNAL` liquida todo el intercambio justo después de la respuesta, y ese webhook ya informa `COMPLETED` (o `COUNTERPARTY_MISMATCHED_DATA`). Cuando el nombre no coincide, tu transferencia queda en `COUNTERPARTY_MISMATCHED_DATA` y el otro cliente no recibe nada.
Sin `counterparty_vasp_email`, y cuando ni los canales ni la [atribución](#atribución-mediante-análisis-de-blockchain) pueden llegar al beneficiario, la transferencia termina más adelante en `COUNTERPARTY_VASP_NOT_FOUND` con una acción `wallet_ownership` en la transacción.

> [!NOTE]
>
> El objeto `travel_rule` incrustado en la transacción contiene los campos propios de la transferencia (`uuid`, `status`, `protocol`, `required`, `obligations_count`, `originator_data`, `beneficiary_data`, `metadata`), lo que Didit resolvió y comparó (`chain_details`, `name_match`, `data_match`, `mismatched_fields`, y los campos de [enmascaramiento](#datos-de-la-contraparte-enmascarados) `data_masked` y `data_unmasked`), y los campos que indican en qué punto se encuentra: `direction`, `rail`, `counterparty_vasp`, `delivery`, `discovery`, `reason` y `next_actions` (consulta [Por qué una transferencia está bloqueada](#por-qué-una-transferencia-está-bloqueada)).
> Cada fila de [`GET /v3/transactions/`](https://docs.didit.me/es/management-api/transactions/list) incluye el mismo bloque, o `null` para una transacción sin transferencia.
> Los endpoints dedicados de transferencias que se describen a continuación también devuelven esos campos, además de `ivms_version`, `ownership_confirmed`, `deadline_at`, `timeline` y `created_at`, pero no `obligations_count` ni `metadata`.

Para cerrar una transferencia saliente en `COMPLETED` una vez que la hayas difundido on-chain:

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"payment_txn_id": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"}'
```

Esto requiere que la transferencia sea **saliente** y esté en estado `COMPLETED`; de lo contrario, la API devuelve `409`.
Si tiene éxito, tanto la transferencia saliente como su contraparte del canal `INTERNAL` pasan a `FINISHED`, y el `payment_txn_id` de la transacción toma el valor del hash que proporcionaste.
En el canal `TRP`, Didit también publica el hash en el callback de confirmación de la contraparte.

Para cancelar una transferencia que aún no ha llegado a un estado final, envía en su lugar `{"action": "cancel"}` al mismo endpoint.
La contraparte del canal `INTERNAL` también se cancela y, en el canal `TRP`, una vez que la contraparte ha aprobado la consulta, Didit publica la cancelación en su callback de confirmación.
Una transferencia que ya está en `FINISHED`, `CANCELLED` o `EXPIRED` devuelve `409`.
Una solicitud sin `payment_txn_id` ni una `action` compatible devuelve `400`.

En una transferencia que pasó por `GTR`, `VERIFYVASP` o `SYGNA`, Didit notifica a la red el hash on-chain (o la cancelación) después de la respuesta, con los [mismos reintentos](#entrega-y-reintentos); el campo `delivery` de la respuesta muestra ese mensaje.

Para reintentar una transferencia saliente que no pudo llegar a su contraparte (una que esté actualmente en `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE` o `NOT_ENOUGH_COUNTERPARTY_DATA`), primero mejora los datos de la contraparte, por ejemplo, añadiendo una `travel_address` a la entrada de la wallet de destino o un [contacto](#contactos) a la entrada del directorio de la contraparte, o catalogando el VASP en el [directorio](#directorio).
Después, envía `{"action": "resend"}` al mismo endpoint.
Didit reinicia el plazo de confirmación y vuelve a poner en cola la secuencia de enrutamiento desde el principio, con los datos almacenados en la transferencia: la respuesta muestra la transferencia de nuevo en `AWAITING_COUNTERPARTY` (con `resend queued` en su `timeline`), y el resultado llega como un webhook `travel_rule.status.updated`.
Un reenvío solicitado mientras aún se ejecuta un intento anterior se envía cuando ese intento concluye.
Cualquier otro estado, o una transferencia entrante, devuelve `409`.

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "resend"}'
```

Para indicar tú mismo la contraparte cuando el [descubrimiento](#descubrimiento-de-la-contraparte) no pudo hacerlo, envía `{"action": "beneficiary_vasp", "beneficiary_vasp": "<directory VASP id>"}` (el `id` de `GET /v3/travel-rule/vasps/`).
La transferencia se enruta a ese VASP y se envía de nuevo.
Solo la acepta una transferencia saliente en `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE` o `NOT_ENOUGH_COUNTERPARTY_DATA`; cualquier otro estado devuelve `409`, y un id desconocido devuelve `404`.

### Por qué una transferencia está bloqueada

Una transferencia en `COUNTERPARTY_VASP_NOT_FOUND` o `COUNTERPARTY_VASP_NOT_REACHABLE` indica por qué está bloqueada y qué la hace avanzar, en cada lectura de su transacción.
Lo incluyen el bloque `travel_rule` de [`GET /v3/transactions/{transaction_id}/`](https://docs.didit.me/es/management-api/transactions/get), el de la respuesta `201` de [`POST /v3/transactions/`](https://docs.didit.me/es/management-api/transactions/create) y el de cada fila de [`GET /v3/transactions/`](https://docs.didit.me/es/management-api/transactions/list), así como el objeto de transferencia con el que responde el [endpoint de transferencias](https://docs.didit.me/es/management-api/travel-rule/update-transfer.md):

* `reason` es la causa legible por máquina, `""` para cualquier otro estado.
* `next_actions` enumera lo que hace avanzar la transferencia, `[]` para cualquier otro estado.
* `delivery` es el mensaje más reciente que la transferencia debe a la otra parte: `kind`, `status` (`QUEUED`, `SENDING`, `RETRYING`, `DELIVERED` o `FAILED`), `rail`, `attempts`, `last_error`, `next_attempt_at` y `delivered_at`, o `null` cuando no ha debido ninguno.
* `discovery` indica dónde buscó Didit la contraparte, con una entrada por cada paso que ejecutó: `step`, `outcome` (`match`, `miss` o `skipped`), `reason`, `vasp`, `rail` y `at`.

`email_undeliverable` y `delivery_failed` provienen de una entrega fallida y solo aparecen en `COUNTERPARTY_VASP_NOT_REACHABLE`.
Una entrega fallida determina `reason` en primer lugar, de modo que una contraparte que Didit sí encontró nunca se notifica como una que no pudo encontrar.
Los otros cuatro provienen de la traza de descubrimiento, en cualquiera de los dos estados.

| `reason` | Qué ocurrió | `next_actions` |
| - | - | - |
| `email_undeliverable` | El proveedor de correo rechazó el correo de cumplimiento y no queda ninguna dirección por intentar: al enviarlo, en un recordatorio o como rebote permanente notificado más tarde. | `update_compliance_email` y después `resend` |
| `delivery_failed` | El rail que realizaba la entrega falló de forma definitiva: un rail de red rechazó el mensaje o agotó los reintentos, un host de identidad `TRP` no respondió o el host `TRP` de la contraparte no aceptó la consulta. | `resend` |
| `awaiting_end_user` | Ningún paso de descubrimiento identificó una contraparte a la que Didit pueda llegar, así que se pide al usuario final que la indique. | `select_counterparty_vasp`, `declare_self_hosted`, `add_vasp_hint`, `resend` |
| `directory_match_no_route` | Un paso identificó una entrada del [directorio](#directorio), pero esa entrada no tiene ninguna ruta que Didit pueda usar por ti. | Igual que `awaiting_end_user` |
| `picked_member_without_proven_wallet` | El usuario final eligió a otro cliente de Didit como contraparte, pero ese cliente no ha demostrado el control de la wallet. | Igual que `awaiting_end_user` |
| `no_directory_match` | La traza de descubrimiento no da ningún otro motivo. | Igual que `awaiting_end_user` |

| Siguiente acción | Qué hacer |
| - | - |
| `update_compliance_email` | Vuelve a indicar el correo de cumplimiento de la contraparte, con `{"action": "update_compliance_email", "compliance_email": "..."}` en el endpoint de la transferencia. |
| `resend` | Vuelve a ejecutar el enrutamiento con `{"action": "resend"}` una vez que algo haya cambiado. |
| `select_counterparty_vasp` | El usuario final elige el VASP de destino en el [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md). `url` es el enlace del widget mientras la transferencia tenga una sesión de widget abierta. |
| `declare_self_hosted` | El usuario final declara en el widget que la wallet es sin custodia, en la misma `url`. |
| `add_vasp_hint` | Indica a Didit quién es la contraparte, con un nombre de VASP, un LEI o una travel address (por ejemplo, un `travel_address` en la [entrada de la libreta de direcciones](#libreta-de-direcciones-de-wallets) de la wallet de destino), y después reenvía. |

Un reenvío hace avanzar la transferencia, por lo que su `reason` se borra.
La entrada de la línea de tiempo de una transición causada por una entrega fallida lleva el mismo valor en `reason`.

Si el proveedor de correo rechaza el correo de cumplimiento de la [transferencia de ejemplo anterior](#enviar-una-transferencia), el bloque `travel_rule` de su transacción queda así, de forma abreviada:

```json theme={null}
{
  "uuid": "33333333-4444-5555-6666-777777777777",
  "status": "COUNTERPARTY_VASP_NOT_REACHABLE",
  "protocol": "EMAIL",
  "direction": "OUTBOUND",
  "rail": "EMAIL",
  "counterparty_vasp": null,
  "delivery": {
    "kind": "SEND",
    "status": "FAILED",
    "rail": "EMAIL",
    "attempts": 1,
    "last_error": "email undeliverable",
    "next_attempt_at": null,
    "delivered_at": null
  },
  "reason": "email_undeliverable",
  "next_actions": [
    { "action": "update_compliance_email" },
    { "action": "resend" }
  ]
}
```

Aquí `delivery` coincide con `reason`, porque el propio envío fue rechazado.
Un rechazo en un recordatorio, o un rebote notificado más tarde, deja `delivery.status` en `DELIVERED`: el primer correo sí se envió.
Consulta `reason`, no `delivery`, para saber por qué una transferencia está bloqueada.

Para solucionarlo, vuelve a indicar el correo de cumplimiento de la contraparte y después reenvía:

```bash theme={null}
curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "update_compliance_email", "compliance_email": "desk@bene-casp.example"}'

curl -X PATCH https://verification.didit.me/v3/transactions/22222222-3333-4444-5555-666666666666/travel-rule/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"action": "resend"}'
```

`update_compliance_email` guarda la dirección como `beneficiary_data.counterparty_vasp_email` de esta transferencia: pertenece solo a esta transferencia y no se añade a ninguna entrada del directorio ni a ninguna lista de contactos.
El estado no cambia, la línea de tiempo añade `compliance email updated` y la transferencia conserva `reason: email_undeliverable` hasta que el reenvío envía la solicitud a la nueva dirección.
Solo la acepta una transferencia saliente en `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE` o `NOT_ENOUGH_COUNTERPARTY_DATA`; cualquier otra transferencia responde `409`, y un `compliance_email` ausente o con formato incorrecto responde `400`.

### Wallets sin custodia declaradas

Cuando tu cliente te indique que el destino es su propia wallet sin custodia (unhosted), decláralo en la transacción en lugar de dejar que el enrutamiento descubra que no hay ningún VASP detrás: establece el tipo de método de pago de la contraparte en `unhosted_wallet`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "trv-2026-07-07-002",
    "transaction_category": "travelRule",
    "transaction_details": {
      "direction": "outbound",
      "action_type": "transfer",
      "amount": "0.25",
      "currency": "ETH",
      "currency_kind": "crypto"
    },
    "subject": {
      "entity_type": "individual",
      "vendor_data": "user-042",
      "full_name": "Jane Doe"
    },
    "counterparty": {
      "entity_type": "external",
      "full_name": "Jane Doe",
      "payment_method": {
        "method_type": "unhosted_wallet",
        "account_id": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9"
      }
    },
    "travel_rule_details": {
      "status": "AWAITING_COUNTERPARTY",
      "beneficiary_data": {
        "wallet_address": "0xd3b62acb76fb27a7f8961ec40fa11746b113aca9",
        "name": "Jane Doe"
      }
    }
  }'
```

La declaración omite por completo el enrutamiento:

* No se intenta ningún rail (no hay ningún VASP de contraparte con el que intercambiar datos) y la transferencia se crea directamente en `UNCONFIRMED_OWNERSHIP`.
* Cuando `auto_wallet_verification` está activado (el valor predeterminado), Didit genera automáticamente una sesión del [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) vinculada a la transacción y la devuelve en el bloque `action_required` de la transacción; los SDK la lanzan automáticamente en el [envío desde el cliente](https://docs.didit.me/es/transaction-monitoring/sdk-transaction-submission.md).
* Una vez que el cliente demuestra el control de la wallet, la transferencia ejecuta la coincidencia del nombre del beneficiario y avanza a `COMPLETED` (o a `COUNTERPARTY_MISMATCHED_DATA` si la coincidencia falla).

Esta es la obligación de la EU TFR sobre wallets sin custodia en forma de API: verificar la propiedad de la wallet sin custodia en lugar de intercambiar datos con un VASP de contraparte.
La declaración se lee del método de pago del lado de **destino** de una transferencia saliente y del lado de **origen** de una entrante; en ambos casos, el participante de la contraparte.
Una transferencia declarada como sin custodia ya está en su ruta final sin rail, por lo que `UNCONFIRMED_OWNERSHIP` no es un estado que admita reenvío: completa la prueba de propiedad (o cancela) en lugar de llamar a `action: "resend"`.

## Recepción

### Confirmar la propiedad de la wallet

Una transferencia queda en espera en `UNCONFIRMED_OWNERSHIP` en dos casos:

* Una transferencia entrante se asocia a una entrada de la [libreta de direcciones](#libreta-de-direcciones-de-wallets) cuya propiedad todavía no está verificada.
* La wallet de la contraparte se declaró sin custodia (`counterparty.payment_method.method_type: "unhosted_wallet"`), en un retiro saliente o en un depósito entrante. Consulta [Wallets sin custodia declaradas](#wallets-sin-custodia-declaradas).

Tu aplicación confirma o rechaza la transferencia:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/{transaction_uuid}/travel-rule/ownership/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"confirmed": true}'
```

El cuerpo admite `confirmed` (obligatorio, booleano) y un `wallet_address` opcional.

El endpoint acepta una transferencia en cualquiera de estos estados y devuelve `409` con `{"detail": "Transfer is not awaiting ownership confirmation."}` en cualquier otro caso:

* `UNCONFIRMED_OWNERSHIP`, en cualquier dirección.
* `ON_HOLD` en una transferencia entrante.
* `UNCONFIRMED_OWNERSHIP`, `ON_HOLD` o `COUNTERPARTY_MISMATCHED_DATA` en una transferencia `TRP` entrante, para que un responsable de cumplimiento pueda resolver manualmente una consulta de la contraparte.

En una transferencia que creó el propio Didit (rail `INTERNAL`, registro sunrise o una wallet sin custodia declarada):

* `confirmed: true` marca como verificada en propiedad la entrada correspondiente de la libreta de direcciones de wallets y, a continuación, ejecuta la coincidencia de nombre con el `holder_name` de esa entrada: `COMPLETED` si la supera, `COUNTERPARTY_MISMATCHED_DATA` si no.
  La transferencia equivalente en el rail `INTERNAL`, cuando existe, obtiene el mismo resultado.
  En una wallet sin custodia declarada, `confirmed: true` registra que tu cliente verificó quién controla la wallet de la contraparte y completa la transferencia (`COMPLETED`), ya sea saliente o entrante.
  Una transferencia entrante cuyo depósito ya se liquidó pasa entonces directamente a `FINISHED`.
* `confirmed: false` mueve ambos lados de la transferencia a `COUNTERPARTY_VASP_GENERAL_DECLINE`.
* La entrada correspondiente se busca en tu propia libreta de direcciones solo por la dirección de la wallet, sin tener en cuenta la cadena.
  Al resolver una transferencia entrante en `ON_HOLD` sin entrada correspondiente, se crea la entrada a partir del `beneficiary_data.wallet_address` de la transferencia y se marca como verificada.
  Una wallet sin custodia declarada es la excepción: la wallet se registra en tu libreta de direcciones como verificada en propiedad, tal como se describe más abajo.
  En cualquier otro caso, una entrada inexistente devuelve `409` con `{"detail": "wallet address entry no longer available"}`, que es también lo que devuelve una entrada eliminada.

En una transferencia `TRP` entrante, la misma llamada responde a la consulta de la contraparte:

* `confirmed: true` necesita una dirección de pago que devolver, que se toma del `wallet_address` de la solicitud, después de la entrada asociada y después de `beneficiary_data.wallet_address`.
  Si no hay ninguna de las tres, la solicitud devuelve `400` con `{"wallet_address": ["wallet_address is required to approve."]}`.
  Didit crea o verifica la entrada, envía a la contraparte el callback de resolución de la consulta, establece `ownership_confirmed` y mueve la transferencia a `COMPLETED`.
* `confirmed: false` envía una resolución de rechazo y mueve la transferencia a `COUNTERPARTY_VASP_GENERAL_DECLINE`.
* Si no se puede contactar con el endpoint de callback de la contraparte, la solicitud devuelve `502` y la transferencia conserva su estado actual.
  En una aprobación, la entrada de la libreta de direcciones de wallets se crea o se marca como verificada de todos modos.

En una wallet sin custodia declarada, la wallet que verificas es la de la contraparte: el destino de un retiro saliente o el origen (la wallet del ordenante) de un depósito entrante.
Didit la añade a la libreta de direcciones de wallets como verificada en propiedad a nombre de la contraparte, de modo que la wallet se compara con el nombre de la contraparte (el ordenante, en un depósito).
Si la libreta de direcciones ya contiene esa wallet con un titular distinto, la transferencia pasa en su lugar a `COUNTERPARTY_MISMATCHED_DATA`.

Si la transferencia no indica ninguna wallet de la contraparte, pasa `wallet_address` en el cuerpo de la solicitud.
Cuando ni la transferencia ni la solicitud aportan una dirección de wallet, la solicitud se rechaza con `400`.

```json theme={null}
{"confirmed": true, "wallet_address": "0xCounterpartyWallet01"}
```

* Una transferencia de red que ya se respondió a través de su red (una transferencia de VerifyVASP, o una transferencia de GTR o Sygna Bridge ya decidida) devuelve `409` (consulta [Transferencias desde una red](#transferencias-desde-una-red)).

La respuesta es el objeto de transferencia completo descrito anteriormente.
Una transferencia `INTERNAL` nueva nunca queda en espera aquí: solo llega a un cliente que ya demostró la propiedad de la wallet. Una transferencia `INTERNAL` más antigua que siga en espera desde antes de esa regla mantiene ocultos los datos del remitente hasta que demuestres el control de la wallet (un mensaje firmado o un depósito de prueba), y confirmarla responde `409` hasta que lo hagas. Rechazarla sigue funcionando.
Cuando la contraparte respondió que la wallet es sin custodia (hoy la [Didit Test VASP](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) da esa respuesta en sandbox), confirmar añade la wallet a tu libreta de direcciones a nombre del beneficiario y ejecuta la coincidencia de nombre: si coincide, la transferencia se completa y la wallet se marca como verificada.

### Transferencias desde una red

Didit también puede recibir transferencias de Travel Rule que una contraparte envía a través de `GTR`, `VERIFYVASP` o `SYGNA`.
Didit activa la recepción para cada red por separado y **hoy no hay ninguna activada**: también requiere que cada red registre los endpoints de Didit, y Didit todavía no es miembro de estas redes.
No se pueden recibir transferencias `TRUST`.

Una vez activada una red, un mensaje que entrega se gestiona así:

* **Enrutamiento.** El mensaje llega a tu aplicación cuando indica el código de participante de tu propia membresía conectada en esa red. Un mensaje dirigido a la membresía propia de Didit solo te llega cuando eres el único cliente activo de Didit que demostró el control de la wallet del beneficiario. Todo lo demás se rechaza, de modo que ningún cliente recibe nunca la transferencia de otro cliente.
* **Decisión.** Didit crea la transferencia entrante en tu aplicación y la decide como una [consulta TRP](https://docs.didit.me/es/transaction-monitoring/travel-rule-interoperability.md#endpoints-de-trp): coincidencia de wallet, propiedad, coincidencia de nombre e `inbound_auto_accept`.
* **Una sola vez.** Las redes reenvían un mensaje hasta que se responde. Una repetición recibe la misma respuesta que recibió la primera copia, y nada se crea ni se decide dos veces.
* **Tu revisión, a través de `GTR` y `SYGNA`.** Una transferencia que queda a la espera de tu decisión (`UNCONFIRMED_OWNERSHIP`, `ON_HOLD` o `COUNTERPARTY_MISMATCHED_DATA`) se decide con [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet): `confirmed: true` la aprueba (pasa `wallet_address` cuando la transferencia no indica ninguna) y `confirmed: false` la rechaza. Didit responde a la red después de la respuesta, con los [mismos reintentos](#entrega-y-reintentos). Una transferencia que ya se respondió devuelve `409`.
* **Sin respuesta posterior a través de `VERIFYVASP`.** VerifyVASP obtiene su respuesta en el momento en que pregunta, por lo que una transferencia que necesitaría tu revisión se rechaza de inmediato y no se puede decidir más tarde (`409`).

### Datos de la contraparte enmascarados

Hasta que se confirma la propiedad de la wallet, los datos personales de la contraparte en una transferencia entrante se devuelven enmascarados en lugar de omitirse.
Se conserva la primera letra de cada palabra, y la wallet, la cadena y el enrutamiento del VASP siguen siendo legibles.
`data_masked` es `true`, y la contraparte en el detalle de la transacción, en el listado y en la exportación CSV se enmascara de la misma forma.

Una vez confirmada la propiedad, aparecen los valores reales y `data_unmasked` registra la entrada de auditoría:

```json theme={null}
{
  "data_masked": false,
  "data_unmasked": { "at": "2026-10-17T10:00:00Z", "reason": "wallet_proof", "actor": "" }
}
```

`reason` es `ownership_confirmed`, `wallet_proof`, `address_book_match`, `own_verified_wallet`, `inquiry_approved` (aprobaste una consulta `TRP` o un mensaje `GTR` o `Sygna`), `known_payment_method` (respondió la wallet del usuario final que consta en tus propios registros) o `travel_address` (la travel address de la wallet identificó la wallet).
Una transferencia entrante `INTERNAL` incluye `data_unmasked` con `reason: wallet_proof` desde el momento en que se crea, porque solo un destinatario que haya demostrado el control de la wallet la recibe.
`actor` es el correo electrónico del usuario de la consola o la etiqueta de la clave de API, y queda vacío cuando la decisión es automática.
El informe **Registro de transferencias de la Travel Rule** (CSV y PDF) enmascara los nombres de una transferencia entrante de la misma forma hasta que se confirma la propiedad. Los informes que presentas ante un regulador, como el XML de goAML y el PDF del informe regulatorio, incluyen los datos reales de la contraparte.

### Información sobre discrepancias

Una transferencia `COUNTERPARTY_MISMATCHED_DATA` ahora indica los campos que difieren.
`data_match` contiene la comparación y `mismatched_fields` enumera los campos.
Ambos incluyen solo nombres de campos y resultados, nunca valores, así que siguen siendo legibles mientras los datos están enmascarados:

```json theme={null}
{
  "status": "COUNTERPARTY_MISMATCHED_DATA",
  "mismatched_fields": ["date_of_birth"],
  "data_match": {
    "matched": false,
    "mismatched_fields": ["date_of_birth"],
    "fields": {
      "name": { "result": "matched", "strictness": "DEFAULT" },
      "date_of_birth": { "result": "mismatched", "strictness": "STRICT" },
      "address": { "result": "not_compared", "strictness": "NONE" },
      "account": { "result": "matched", "strictness": "STRICT" }
    }
  }
}
```

La entrada de la línea de tiempo indica los campos, por ejemplo "beneficiary date of birth does not match wallet holder".
Un rechazo `TRP` tras una discrepancia indica al VASP ordenante qué campos difieren, por ejemplo "Beneficiary data does not match the wallet holder: name".
Lo que el otro VASP llega a saber está limitado a propósito: mientras el nombre sea incorrecto, el nombre es el único campo que se informa (`mismatched_fields: ["name"]`, y todos los demás campos `not_compared`), y una vez que el nombre coincide, se indican todos los campos que difieren. Esto se aplica al lado del remitente en un intercambio `INTERNAL` y a un rechazo `TRP`.
Un nombre que falta en ambos lados aparece como `not_compared` y no cuenta como discrepancia, y un país coincide por el país al que se refiere, así que `ES` y `ESP` concuerdan.

#### Puntuación de coincidencia del nombre

Toda transferencia cuyo nombre se comparó incluye `name_match`, y la entrada de la línea de tiempo que lo decidió incluye el mismo objeto junto a su `detail`:

```json theme={null}
{
  "name_match": {
    "score": 90,
    "matched": false,
    "method": "sequence_ratio",
    "strictness": "FUZZY",
    "compared_with": "wallet_holder",
    "transfer_name": "Ana Diaz",
    "compared_name": "Ana Diaz Garcia",
    "matched_names": ["Ana", "Diaz"],
    "mismatched_names": ["Garcia"]
  }
}
```

* `score` es la similitud entre los dos nombres completos, de 0 a 100, y `0` cuando alguno de ellos está vacío. `matched` es el resultado según `strictness`, por lo que ambos pueden no coincidir: `FUZZY` decide según su propio índice de similitud de `0.85`.
* `matched_names` son las palabras del nombre de la transferencia que se encuentran en el otro nombre; `mismatched_names` son las palabras que tiene uno de los lados y le faltan al otro.
* `method` es `none`, `exact_token`, `token_subset`, `token_containment` o `sequence_ratio`, para `NONE`, `STRICT`, `DEFAULT`, `CONTAINS` y `FUZZY`.
* `compared_with` es `wallet_holder` (el titular registrado para la wallet) o `counterparty_vasp` (el nombre que respondió la contraparte en la página de respuesta por correo electrónico, o la respuesta del Didit Test VASP).
* El resultado de la transferencia depende de `data_match`, que compara todos los campos, así que una transferencia puede ser `COUNTERPARTY_MISMATCHED_DATA` mientras `name_match.matched` es `true`.
* `name_match` está en el objeto de transferencia que devuelven los endpoints de la Travel Rule y en el `travel_rule` incrustado de la transacción, y es `null` hasta que se compara un nombre. El listado de transferencias y los webhooks no lo incluyen.
* Los nombres se ocultan mientras las partes están [enmascaradas](#datos-de-la-contraparte-enmascarados), y en la copia del otro cliente de un intercambio `INTERNAL`.

### Mensajes y solicitudes de documentos

Dos VASP pueden resolver una transferencia en disputa dentro de Didit en lugar de por correo electrónico.
`GET` y `POST /v3/transactions/{transaction_id}/travel-rule/messages/` listan y envían mensajes en una transferencia:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/transactions/{transaction_uuid}/travel-rule/messages/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind": "DOCUMENT_REQUEST", "body": "Please confirm the beneficiary date of birth.", "requested_documents": ["Proof of address"]}'
```

* `kind` es `MESSAGE` (valor predeterminado) o `DOCUMENT_REQUEST`. Una solicitud de documentos necesita al menos una entrada en `requested_documents` (hasta 10); un mensaje necesita un `body` (hasta 5000 caracteres) o un archivo.
* `reply_to` indica un mensaje anterior de la misma transferencia. Una respuesta del otro lado que incluya un documento cumple la solicitud de documentos a la que responde, y se establece `fulfilled_at` en ella. Tu propia respuesta nunca cumple tu propia solicitud.
* Envía multipart con `files` para adjuntar hasta 5 archivos de 10 MB cada uno, en PDF, PNG, JPEG o WebP. Didit comprueba el contenido de cada archivo, no solo su tipo declarado, y cualquier otro archivo responde `400` en `files` ("Attach PDF, PNG, JPEG or WebP files only.").
* Una transferencia admite hasta 100 mensajes, de los cuales hasta 20 pueden llevar adjuntos (cada uno con hasta 5 archivos), contando ambos lados; si se supera cualquiera de los dos límites, la solicitud responde `400`. Los adjuntos de los mensajes no cuentan para los documentos propios de una transacción.
* Los mensajes funcionan en los canales `INTERNAL` y `EMAIL`. En `INTERNAL`, el otro cliente de Didit ve el mensaje en su lado del par. En `EMAIL`, se envía un correo electrónico a la contraparte, que responde en el portal de recogida. Si ese correo de notificación no se puede enviar, el mensaje se guarda de todos modos y la solicitud responde `201`.
* La solicitud responde `409` con un motivo en `detail` para una transferencia por `TRP`, `GTR`, `TRUST`, `VerifyVASP` o `Sygna` (esos protocolos no admiten mensajes), una transferencia que aún no tiene contraparte, una transferencia `INTERNAL` cuyos datos no coincidieron con el titular de la wallet (no llegó nada al destinatario), una transferencia `INTERNAL` cuyo destinatario aún no ha demostrado el control de la wallet (en ambos lados, hasta que lo haga), una transferencia `EMAIL` cuya contraparte ya no tiene una dirección de correo electrónico de cumplimiento, y una transferencia `EMAIL` cuyo enlace de recogida ha expirado o cuya transferencia está cerrada.
* No se dispara ningún webhook cuando la contraparte responde. Consulta el endpoint de mensajes.
* El correo electrónico que avisa a la contraparte de un nuevo mensaje se envía en inglés.

### Libreta de direcciones de wallets

Registra las wallets que controlas para que las transferencias entrantes (canal `INTERNAL`, consultas `TRP` entrantes y [registros posteriores al depósito](#registro-sunrise-posterior-al-depósito)) puedan resolverse con ellas, con `POST`/`GET /v3/travel-rule/wallet-addresses/` y `PATCH`/`DELETE /v3/travel-rule/wallet-addresses/{entry_uuid}/`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/wallet-addresses/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
    "chain": "ETH",
    "holder_name": "Ana Diaz",
    "holder_vendor_data": "user-042",
    "self_declared": true
  }'
```

| Campo | Tipo | Descripción |
| - | - | - |
| `address` | string | La dirección de la wallet. Es única por aplicación, `chain` y `memo` (la dirección se compara sin distinguir mayúsculas de minúsculas); un duplicado devuelve `400`. Una X-address de XRP se almacena como su dirección clásica y su tag. Está vacía en una entrada [importada por su hash](#importar-wallets-de-forma-masiva). |
| `address_hash` | string | Solo lectura. SHA-256 de la dirección en minúsculas, en hexadecimal en minúsculas. |
| `memo` | string | Opcional. El destination tag o memo que forma parte de la wallet en una [red con memo](#redes-con-memo-y-etiqueta); vacío para la dirección completa. Alias: `destinationTag`. |
| `chain` | string | Identificador de cadena opcional, de hasta 32 caracteres. Usa el mismo token que llevan tus transferencias (por ejemplo, `ETH` o `BTC`), o déjalo vacío para que coincida con transferencias en cualquier cadena; consulta la nota más abajo. Un beneficiario de Lightning (node id o Lightning Address) registrado en bitcoin se almacena en minúsculas en `LIGHTNING`, donde se buscan las coincidencias de las transferencias [Lightning](#lightning). |
| `holder_name` | string | Nombre del titular de la wallet, que se usa para la coincidencia del nombre del beneficiario. |
| `holder_vendor_data` | string | Tu identificador interno del titular. |
| `entity_type` | string | Texto libre de hasta 16 caracteres; el valor predeterminado es `"individual"`. |
| `travel_address` | string | Opcional. La travel address del VASP de la contraparte para esta wallet, si la conoces. Permite que Didit enrute las transferencias a este beneficiario por el rail `TRP` en lugar de por correo electrónico. |
| `receiving_travel_address` | string | Solo lectura. Tu propia travel address por wallet para esta wallet. Dásela a un VASP que envíe a esta wallet: así su consulta TRP nombra la wallet directamente. Está vacía para una wallet registrada como de otro VASP, mientras Travel Rule está desactivada y antes de que se guarde tu perfil de VASP. Deja de responder en cuanto se elimina la wallet. |
| `is_ownership_verified` | boolean | Solo lectura. Indica si se ha demostrado la propiedad de esta dirección (mediante el [widget de propiedad de wallets](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) o la autodeclaración). |
| `self_declared` | boolean | Solo escritura, solo en `POST`. Cuando es `true`, la entrada se crea ya verificada mediante una prueba `SELF_DECLARATION`: las transferencias entrantes a esta dirección omiten por completo `UNCONFIRMED_OWNERSHIP` y pasan directamente a la coincidencia de nombre. Devuelve `400` cuando `allow_self_declaration` está desactivado en tu configuración. |

`PATCH` acepta `holder_name`, `holder_vendor_data`, `entity_type` y `travel_address`, y devuelve solo esos cuatro campos.
`DELETE` elimina la entrada (`204`): su dirección queda libre para volver a registrarse y deja de coincidir de inmediato con nuevas transferencias.

> [!NOTE]
>
> La coincidencia no distingue mayúsculas de minúsculas en la dirección, incluye su `memo` en una red con memo y está acotada por `chain`.
> Cuando una transferencia lleva una cadena, una entrada solo coincide si su `chain` tiene el mismo valor (sin distinguir mayúsculas de minúsculas) o está vacío.
> Los nombres de cadena se comparan como texto, sin traducirse, así que una entrada almacenada como `ethereum` no coincide con una transferencia cuya cadena es `ETH`.
> Las transferencias salientes toman su cadena de `beneficiary_data.chain`, después de `transaction_details.crypto_params.crypto_chain`, después de `custom_properties.crypto_chain` y después de la moneda (por ejemplo, `ETH`, o, para `USDT` y `USDC`, la cadena inferida de `payment_reference_id`), que solo se establece cuando es una cadena que Didit reconoce; los registros posteriores al depósito la toman de su campo `chain`, en minúsculas.
> Las consultas `TRP` entrantes ignoran la cadena: buscan coincidencias por dirección o, cuando la consulta no nombra ninguna wallet, por el nombre del beneficiario frente a tus entradas verificadas.
> [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet) también busca coincidencias solo por dirección.
> Cuando coinciden varias entradas, el rail `INTERNAL` y los registros posteriores al depósito prefieren una entrada con propiedad verificada y, después, la más antigua, y la búsqueda `TRP` saliente toma la entrada más antigua que almacene una travel address.
> Las consultas `TRP` entrantes y el endpoint de propiedad toman cualquiera de las entradas coincidentes, así que mantén una sola entrada por dirección siempre que puedas.
> El rail `INTERNAL` no coincide con ninguna entrada cuando existen entradas verificadas para la dirección en más de una aplicación distinta.

#### Importar wallets de forma masiva

Importa hasta 10,000 wallets en una sola llamada con [`POST /v3/travel-rule/wallet-addresses/import/`](https://docs.didit.me/es/management-api/travel-rule/import-wallet-addresses), en JSON (`{"entries": [...]}` o un array sin envolver) o como archivo CSV en UTF-8 de 5 MB como máximo, con una fila de encabezado.
Cada fila identifica una wallet por su `address`, por `address_hash` (el SHA-256 de la dirección en minúsculas, de 64 caracteres hexadecimales o 44 en base64) o por ambos, junto con cualquiera de los campos de entrada anteriores.
Envía solo el hash para registrar una wallet sin revelar su dirección: coincide con las transferencias a esa dirección como cualquier otra entrada y su propiedad puede demostrarse con el [widget de propiedad de wallets](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md).

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/wallet-addresses/import/ \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@wallets.csv;type=text/csv"
```

```text theme={null}
address,address_hash,chain,memo,holder_name,holder_vendor_data
0xBeneficiaryWallet01,,ethereum,,Ana Diaz,user-042
,4f7d2e1c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e,bitcoin,,,user-043
rExchangeSharedAddress01,,XRP,104729,Ana Diaz,user-042
```

La importación es idempotente e informa de cada fila en el orden en que se envió: `created`, `existing` (la misma wallet, cadena y memo ya está en la libreta y no se modificó), `duplicate` (repite una fila anterior, indicada en `duplicate_of_row`) o `failed` con sus `errors`.
Una fila errónea nunca hace fallar a las demás: la respuesta es `200` cuando no ha fallado ninguna fila y `207` cuando ha fallado alguna, con los recuentos en `total`, `created`, `existing`, `duplicate` y `failed`.
Una celda vacía del CSV cuenta como no enviada y las columnas que la importación no lee se ignoran, así que una exportación de otra herramienta se importa tal cual.

En `GET /v3/travel-rule/transfers/`, cada fila incluye `originator_memo` y `beneficiary_memo` junto a las dos wallets.

### Recogida por correo electrónico para contrapartes inalcanzables

Cuando ningún rail de protocolo puede llegar a la contraparte, Didit recurre a `EMAIL`: envía un enlace de recogida de un solo uso a `beneficiary_data.counterparty_vasp_email` (o a un correo electrónico obtenido a partir de `beneficiary_data.counterparty_vasp_name` en el registro del directorio de VASP).
El destinatario no necesita una cuenta de Didit ni una clave de API: el token del enlace es la autenticación.
Cómo se envía la solicitud:

* **A las direcciones correctas.** Un `counterparty_vasp_email` que pases es el único destinatario. Si no, Didit escribe a hasta tres direcciones: los [contactos](#contactos) de la contraparte que no hayan rebotado (primero los tuyos, después los contactos de la plataforma, con prioridad para los que respondieron antes) y, si queda un hueco, el correo electrónico de cumplimiento de la entrada del directorio. Cada dirección recibe su propio correo.
* **En tu nombre.** El correo sale de la dirección de Didit como "*tu razón social* vía Didit", en el idioma de la jurisdicción de la contraparte (en inglés si no se conoce ninguna), y el enlace abre la página de respuesta en ese idioma. No recibes copia: sigue la cronología de la transferencia.
* **Con recordatorios.** Hasta que la contraparte responde, Didit le envía recordatorios 72, 24 y 6 horas antes de la fecha límite, al menos 12 horas después de la solicitud o del último recordatorio, y nunca después de la fecha límite.
* **Con gestión de rebotes.** Un rebote o una queja por spam marca como no válido el contacto al que llegó, con su motivo, y la cronología de la transferencia lo registra. Un contacto de la plataforma pasa entonces a ser no válido para todos los clientes de Didit; el contacto propio de tu aplicación, solo para tu aplicación. Cuando el servicio de entrega de correo de Didit deja de enviar por completo a una dirección (tras un rebote permanente, una queja por spam o una baja de suscripción), todos los contactos con esa dirección se marcan como no válidos (`suppressed`), y vuelven a ser válidos en cuanto se reanuda el envío a esa dirección. Cuando no queda ninguna dirección a la que escribir, la transferencia pasa a `COUNTERPARTY_VASP_NOT_REACHABLE`, con el motivo del servidor de correo receptor en su cronología. Un rebote permanente o una queja por spam en el `counterparty_vasp_email` que pasaste lo provoca de inmediato, porque es el único destinatario; un rebote temporal (`soft_bounce`) en él, o en el propio correo electrónico de cumplimiento de la entrada del directorio, deja la solicitud abierta para los recordatorios.

El enlace abre una página alojada que muestra el intercambio pendiente y llama a estos dos endpoints públicos en nombre del destinatario.
Para la [transferencia de ejemplo anterior](#enviar-una-transferencia), los datos de recogida son:

```bash theme={null}
curl https://verification.didit.me/v3/travel-rule/pickup/{token}/
```

```json theme={null}
{
  "reference": "33333333-4444-5555-6666-777777777777",
  "requested_at": "2026-07-05T10:00:00Z",
  "originator_vasp_name": "Origin CASP SL",
  "originator_vasp_lei": "529900EXAMPLEORIG001",
  "recipient_vasp_name": "Example Counterparty VASP",
  "language": "es",
  "amount": "0.250000000000000000",
  "currency": "ETH",
  "fiat_amount": "",
  "fiat_currency": "",
  "chain": "ETH",
  "beneficiary_wallet": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
  "status": "AWAITING_COUNTERPARTY",
  "ivms_version": "ivms101.2023",
  "deadline_at": "2026-07-07T10:00:00Z",
  "reminders_sent": 0,
  "contact": "",
  "decline_reasons": ["data_mismatch", "not_our_customer", "wallet_not_hosted", "sanctions", "risk_appetite", "jurisdiction", "insufficient_data", "other"],
  "join_invitation": { "eligible": false, "url": "" },
  "originator_data": { "name": "Jane Doe", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
  "beneficiary_data": { "name": "Ana Diaz", "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb" },
  "ivms_request": {
    "originator": {
      "originatorPersons": [{ "naturalPerson": { "name": { "nameIdentifier": [{ "primaryIdentifier": "Doe", "secondaryIdentifier": "Jane", "nameIdentifierType": "LEGL" }] } } }],
      "accountNumber": ["0x77ccff0cc624a53cd8b8d8703ced826710211ec7"]
    },
    "beneficiary": {
      "beneficiaryPersons": [{ "naturalPerson": { "name": { "nameIdentifier": [{ "primaryIdentifier": "Diaz", "secondaryIdentifier": "Ana", "nameIdentifierType": "LEGL" }] } } }],
      "accountNumber": ["0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb"]
    }
  },
  "data_masked": false
}
```

`reference` es el `uuid` de la transferencia. `originator_data` y la `ivms_request` IVMS 101 creada a partir de él solo incluyen los campos del ordenante que compartes en [`data_sharing_fields`](#compartición-de-datos); el nombre y la wallet se incluyen siempre. `fiat_amount` y `fiat_currency` están vacíos cuando no enviaste ningún valor convertido, `contact` repite el valor `?contact=` del enlace y `decline_reasons` enumera los valores que acepta `decline_reason`. `join_invitation.eligible` es `true` mientras la contraparte tenga una invitación vigente para unirse a Didit; el enlace de invitación en sí solo viaja en el correo electrónico.

Este endpoint devuelve la cantidad almacenada tal cual, por lo que incluye los 18 decimales completos en lugar de la forma recortada que usa el objeto de detalle de la transacción.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/pickup/{token}/respond/ \
  -H "Content-Type: application/json" \
  -d '{"decision": "accept", "beneficiary_name": "Ana Diaz"}'
```

`decision` es `accept` o `decline`.
Con `accept`, el `beneficiary_name` proporcionado se compara con el `beneficiary_data.name` de la transferencia según tu regla de nombres: `COMPLETED` si coinciden y `COUNTERPARTY_MISMATCHED_DATA` en caso contrario. En su lugar, la contraparte puede enviar una respuesta IVMS 101 completa como `ivms_response`; en ese caso, su nombre de beneficiario prevalece sobre `beneficiary_name`.
Con `decline`, la transferencia pasa a `COUNTERPARTY_VASP_GENERAL_DECLINE`. La contraparte puede indicar un `decline_reason` de `decline_reasons`, con un `decline_detail` (hasta 512 caracteres, obligatorio para `other`), y la cronología de tu transferencia lo registra, por ejemplo `counterparty declined: The beneficiary is not our customer`.
La respuesta es el `{"status": "..."}` resultante, más `decline_reason` tras un rechazo. Una vez que la contraparte ha respondido, ambos endpoints devuelven `410`.
Ambos endpoints devuelven `404` para un token desconocido y `410` cuando se cierra la ventana: es decir, cuando la transferencia salió de `AWAITING_COUNTERPARTY` o cuando ya pasó su plazo de confirmación (`confirmation_timeout_hours` después de la creación o del último reenvío).

La contraparte lee y responde a través del enlace de recogida con `GET` y `POST /v3/travel-rule/pickup/{token}/messages/`.
No necesita clave de API, solo acepta adjuntos PDF, PNG, JPEG o WebP y responde `410` cuando el enlace expira o la transferencia se cierra.
Un mensaje que enviaste muestra el nombre de tu VASP como `author` y como `uploaded_by` del adjunto, nunca la persona ni la clave de API que lo envió.

### Depósitos sin emparejar

Un depósito entrante puede llegar antes que los datos de Travel Rule del VASP de origen.
Ese depósito permanece en `AWAITING_COUNTERPARTY` o `NOT_ENOUGH_COUNTERPARTY_DATA` hasta que llegan los datos.
Enumera los depósitos que siguen en espera con una clave de API que tenga el privilegio de transacciones:

```bash theme={null}
curl "https://verification.didit.me/v3/travel-rule/unmatched/" \
  -H "x-api-key: YOUR_API_KEY"
```

La respuesta usa las mismas filas que `GET /v3/travel-rule/transfers/`, limitadas a los depósitos entrantes que esperan los datos del VASP de origen.

Cuando los datos hayan llegado como un mensaje recibido aparte, empareja tú mismo ambos:

```bash theme={null}
curl -X POST "https://verification.didit.me/v3/travel-rule/unmatched/{transaction_uuid}/match/" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": "<uuid of the received message transaction>"}'
```

`{transaction_uuid}` es el depósito.
`transaction_id` es la transacción del mensaje de Travel Rule recibido.
La llamada devuelve `{ "deposit": ..., "message": ... }`.
Responde `404` cuando alguna de las dos transacciones ya no existe, y `409` con `travel_rule_match_conflict` ("This deposit can no longer be matched.") cuando alguna de las dos partes ya ha avanzado.

### Registro sunrise posterior al depósito

Cuando un depósito de criptoactivos se liquida on-chain **antes** de que se haya producido cualquier intercambio de Travel Rule (el VASP emisor no estaba disponible o estás cargando depósitos históricos), regístralo a posteriori con `POST /v3/travel-rule/inbound/`.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/inbound/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": "eth",
    "txid": "0xf103cfc37f6d390b61827987b9dc631b5e1d2bfeb008a780c1e38047ae5d557b",
    "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb",
    "amount": "500.00",
    "currency": "USDC",
    "originator_data": { "name": "Carlos Ruiz", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
    "beneficiary_data": { "name": "Ana Diaz" },
    "originating_vasp": {
      "name": "Northwind Digital Assets Ltd",
      "lei": "5493001KJTIIGC8Y1R12",
      "travel_address": "tareGfwAzkySLkFzcqr7AKno3K4VsT3jayMwPvj3ovbFZHzpayHLmgCrAMoLqjfCYRPpvLqr9dSr2VVTFAncwChcMjL4AheNuHCJM8NRcUg"
    }
  }'
```

`originating_vasp.travel_address` debe ser una [travel address](#direcciones-de-viaje) real y con checksum válido: un valor de marcador de posición devuelve `400` con `"Invalid travel address."`.
`originating_vasp.lei` debe estar vacío o tener 20 caracteres en formato LEI (18 letras o dígitos y, a continuación, 2 dígitos); cualquier otro valor devuelve `400` con `"Invalid LEI: expected 20 alphanumeric characters (ISO 17442)."`.
Didit solo comprueba este formato, no los dígitos de control de ISO 17442.

| Campo | Tipo | Descripción |
| - | - | - |
| `chain` | string | Cadena en la que se liquidó el depósito, hasta 32 caracteres. Didit la convierte a minúsculas y la usa para emparejarla con las entradas de tu [libreta de direcciones](#libreta-de-direcciones-de-wallets), así que usa el mismo token que en tus entradas (`eth` coincide con una entrada guardada como `ETH`). También determina si el depósito puede analizarse: `bitcoin`/`btc`, `ethereum`/`eth`, `solana`/`sol`, `tron`/`trx`, `polygon`/`matic`, `bsc`/`bnb`, `litecoin`/`ltc`, `ripple`/`xrp`, `bitcoin-cash`/`bch` y `dogecoin`/`doge`. |
| `txid` | string | El hash de la transacción on-chain. Se usa para eliminar duplicados: el mismo `txid` + `wallet_address` devuelve la transferencia existente en lugar de crear una duplicada. |
| `wallet_address` | string | La wallet de destino en la que recibiste el depósito. Una X-address de XRP se divide en su dirección clásica y su tag. |
| `memo` | string | Opcional. El destination tag o memo del depósito en una [red con memo](#redes-con-memo-y-etiqueta): en una dirección de depósito compartida, identifica al cliente al que pertenece el depósito. |
| `amount` | string (decimal) | Cantidad del depósito. |
| `currency` | string | Activo del depósito. |
| `originator_data` | object | Datos del ordenante procedentes del VASP emisor, si se conocen, como objeto plano: Didit lee `name` (o `full_name`), `first_name`, `last_name` y `vendor_data`. |
| `beneficiary_data` | object | Datos del beneficiario (tu cliente), como objeto plano: Didit compara su `name` con el `holder_name` de la entrada de la libreta de direcciones emparejada y le añade `wallet_address` y `chain`. |
| `utxo` | object | Opcional, solo para [cadenas UTXO](#transferencias-utxo). Los `inputs` y `outputs` de la transacción del depósito: la wallet del emisor es `originator_data.wallet_address` cuando la declaras y, si no, el input de mayor valor. |
| `originating_vasp` | object | `{ name, lei, travel_address }` opcional que describe al emisor. `lei` debe cumplir el formato LEI anterior y `travel_address` debe ser una travel address válida; de lo contrario, la solicitud devuelve `400`. Se guarda en esta transferencia como `metadata.originating_vasp`; nunca crea ni modifica una entrada compartida del [directorio](#cómo-se-incorporan-las-entradas-al-directorio). |

Didit crea una transacción `travelRule` entrante (o reutiliza un depósito entrante que ya enviaste con el mismo hash y la misma wallet, si todavía no tiene una transferencia Travel Rule) y concilia la transferencia con tu [libreta de direcciones de wallets](#libreta-de-direcciones-de-wallets), según la dirección y su memo:

* Ninguna entrada coincide -> `ON_HOLD`.
  Resuélvelo con [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet): `confirmed: true` añade la wallet a tu libreta de direcciones como verificada y ejecuta la comprobación del nombre; si el nombre coincide, la transferencia pasa a `COMPLETED` y después a `FINISHED`.
* La entrada existe, pero la propiedad no está demostrada -> `UNCONFIRMED_OWNERSHIP`.
* El nombre del beneficiario no coincide con el `holder_name` de la entrada -> `COUNTERPARTY_MISMATCHED_DATA`.
* La entrada está verificada y el nombre coincide -> `COMPLETED` y, de inmediato, `FINISHED` (el depósito ya se ha liquidado).

Con la entrada verificada de la libreta de direcciones registrada en el [ejemplo anterior](#libreta-de-direcciones-de-wallets), la respuesta es:

```json theme={null}
{
  "transaction_id": "44444444-5555-6666-7777-888888888888",
  "txn_id": "tr-in-0xf103cfc37f6d390b61827987b9dc631b5e1d2bfeb008a780c1e38047ae5d557b-6151d81b366e",
  "created": true,
  "travel_rule": {
    "uuid": "55555555-6666-7777-8888-999999999999",
    "status": "FINISHED",
    "direction": "INBOUND",
    "rail": null,
    "protocol": null,
    "ivms_version": "ivms101.2023",
    "required": true,
    "ownership_confirmed": true,
    "deadline_at": null,
    "timeline": [
      { "status": "COMPLETED", "at": "2026-07-06T10:15:02.114208+00:00", "detail": "matched verified wallet address book entry" },
      { "status": "FINISHED", "at": "2026-07-06T10:15:02.131544+00:00", "detail": "on-chain deposit already settled" }
    ],
    "counterparty_vasp": null,
    "originator_data": { "name": "Carlos Ruiz", "wallet_address": "0x77ccff0cc624a53cd8b8d8703ced826710211ec7" },
    "beneficiary_data": { "name": "Ana Diaz", "wallet_address": "0xede2d7e4f5b097e6391ab6bbcf2f47a53f4778cb", "chain": "eth" },
    "created_at": "2026-07-06T10:15:02.087412Z"
  }
}
```

El `txn_id` de la nueva transacción está formado por `tr-in-`, los primeros 80 caracteres del `txid` y un hash de 12 caracteres del `txid` y la wallet.
`created` es `true` (HTTP `201`) cuando esta llamada registró el depósito, y `false` (HTTP `200`) cuando el mismo `txid` y la misma `wallet_address` ya estaban registrados; en ese caso, se devuelve la transferencia existente sin cambios.
En el caso de una entrada verificada, ambas transiciones ocurren antes de que el endpoint responda, por lo que la respuesta síncrona ya muestra el estado final `FINISHED`; el paso intermedio `COMPLETED` queda igualmente registrado en el `timeline` de la transferencia.
Cada transición dispara un webhook `travel_rule.status.updated` (`COMPLETED` y `FINISHED` disparan uno cada uno).
Si Didit creó una nueva transacción, envía primero [`transaction.created`](https://docs.didit.me/es/integration/webhooks#tipos-de-eventos) y después estos eventos.
El registro no conlleva ninguna tarifa de Travel Rule ni de monitorización.
Cuando la monitorización cripto está activada y la `chain` es una que Didit puede analizar, el depósito recién creado también se analiza y se factura una vez con la tarifa de Verificación y análisis de wallets.

### Widget de propiedad de wallet

Para sacar una transferencia de `UNCONFIRMED_OWNERSHIP`, o para verificar una wallet por adelantado antes de que llegue cualquier transferencia, genera un widget alojado de propiedad de wallet con `POST /v3/travel-rule/widget-session/` y envía a tu cliente a la `url` devuelta. El widget demuestra el control de la wallet mediante la firma de un mensaje (incluidas las cuentas de smart contract EVM, a través de ERC-1271 y ERC-6492), una prueba Satoshi, una captura de pantalla o una autodeclaración, y después marca como verificada la entrada correspondiente de la libreta de direcciones para que el intercambio pueda continuar.
La captura de pantalla es la excepción: nunca verifica la wallet por sí sola, así que tu equipo de cumplimiento la revisa y confirma la transferencia en `UNCONFIRMED_OWNERSHIP` con [`POST .../travel-rule/ownership/`](#confirmar-la-propiedad-de-la-wallet).

Consulta [Widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md) para ver el flujo completo, los métodos de prueba y la nota importante de que el widget debe abrirse en un navegador real, nunca dentro de un webview de un SDK móvil.

## Directorio

`GET /v3/travel-rule/vasps/` busca en el directorio de VASP: las entradas del directorio compartido más los miembros de la [red de Didit](#la-red-de-didit). Cada fila indica cómo puede tu aplicación llegar hoy a ese VASP.

```bash theme={null}
curl "https://verification.didit.me/v3/travel-rule/vasps/?search=counterparty" \
  -H "x-api-key: YOUR_API_KEY"
```

```json theme={null}
{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91",
      "kind": "directory",
      "name": "Example Counterparty VASP",
      "lei": "529900EXAMPLECPTY001",
      "jurisdiction": "DE",
      "domains": ["counterparty.example"],
      "reachable": true,
      "aliases": [{ "name": "Example Counterparty", "kind": "trading_name" }],
      "networks": [
        {
          "network": "GTR",
          "code": "EXAMPLE01",
          "listed_name": "Example Counterparty VASP",
          "country": "DE",
          "verified_at": "2026-10-12T09:30:00Z",
          "last_seen_at": "2026-10-12T09:30:00Z",
          "source": "staff"
        }
      ],
      "routes": [
        { "rail": "GTR", "status": "unavailable", "reason": "no_membership", "via": "" },
        { "rail": "EMAIL", "status": "available", "reason": "", "via": "contact" }
      ],
      "umbrella": null,
      "entities": [],
      "contacts": [
        {
          "id": "6c1f9b8e-2d4a-4f7e-8b3c-5a9d0e1f2a3b",
          "email": "travelrule@counterparty.example",
          "name": "Travel Rule desk",
          "source": "staff",
          "scope": "platform",
          "verified_at": null
        }
      ],
      "dd_status": "NOT_STARTED",
      "dd_score": 62,
      "dd_score_breakdown": {
        "jurisdiction": { "points": 25.0, "max": 25, "reason": "jurisdiction_not_high_risk", "detail": "DEU is not on the high-risk jurisdiction list" },
        "verification": { "points": 3.8, "max": 15, "reason": "dd_status_not_started", "detail": "due diligence status NOT_STARTED" },
        "protocol": { "points": 6.0, "max": 15, "reason": "email_only", "detail": "reachable over the email fallback only" },
        "lei": { "points": 10.0, "max": 10, "reason": "lei_valid", "detail": "valid LEI on record" },
        "history": { "points": 5.0, "max": 10, "reason": "no_history", "detail": "no exchange history" },
        "essentials": { "points": 7.5, "max": 15, "reason": "no_essential_checks", "detail": "no decided essential check yet" },
        "responsiveness": { "points": 5.0, "max": 10, "reason": "responsiveness_unknown", "detail": "0 decided recent requests, too few to judge" }
      },
      "dd_assessed_at": "2026-10-12T09:30:00Z",
      "dd_score_semantic": "higher_is_safer",
      "risk_level": "MEDIUM",
      "responsiveness": { "status": "UNKNOWN", "answered": 0, "total": 0, "computed_at": "2026-10-12T09:30:00Z" },
      "essential_checks": {},
      "reachable_rails": ["GTR", "EMAIL"],
      "is_didit_customer": false,
      "decision": {
        "decision": "APPROVED",
        "reason": "Licensed in DE",
        "decided_by": "",
        "updated_at": "2026-10-14T10:05:00Z",
        "inherited_from": null
      },
      "entity_screening": {
        "id": "7a1d2c3b-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
        "status": "Approved",
        "total_hits": 0,
        "score": null,
        "screened_at": "2026-10-14T09:58:00Z",
        "fresh": true,
        "flagged": false
      },
      "questionnaires": []
    }
  ]
}
```

`search` busca coincidencias con un fragmento de nombre o alias, un LEI exacto o un dominio (`counterparty.example` o una URL de ese dominio). Acota los resultados con:

| Parámetro | Efecto |
| - | - |
| `network` | `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA` o `TRISA`: solo las entradas que figuran actualmente en el directorio de miembros de esa red. |
| `jurisdiction` | Código de país ISO 3166 alfa-2 o alfa-3. |
| `reachable` | `true`: solo los VASP a los que tu aplicación tiene una ruta disponible. `false`: solo las entradas a las que hoy no puede llegar. |
| `kind` | `directory` para las entradas compartidas, `didit` para los miembros de la red de Didit. |
| `risk` | `LOW`, `MEDIUM` o `HIGH`: solo las entradas del directorio cuyo `risk_level` está en esa franja. Consulta [Puntuación y nivel de riesgo](#puntuación-y-nivel-de-riesgo). |
| `responsiveness` | `RESPONSIVE`, `UNRESPONSIVE` o `UNKNOWN`: solo las entradas del directorio con ese `responsiveness.status`. Consulta [Capacidad de respuesta](#capacidad-de-respuesta). |

Los miembros de la red de Didit no reciben puntuación, por lo que `risk` y `responsiveness` solo devuelven entradas del directorio. Los resultados se ordenan por nombre y se paginan con `limit` (por defecto `50`) y `offset`. Una red, un código de país, una franja de riesgo o un estado de capacidad de respuesta desconocidos responden `400` indicando el campo. `GET /v3/travel-rule/vasps/{vasp_id}/` devuelve una fila por su `id`. Tu propio perfil de VASP nunca aparece en tus propios resultados.

`dd_status`, `dd_score`, `dd_score_breakdown`, `dd_assessed_at`, `dd_score_semantic`, `risk_level`, `responsiveness` y `essential_checks` contienen la evaluación de diligencia debida compartida de una entrada del directorio. `decision`, `entity_screening` y `questionnaires` son los registros propios de tu aplicación sobre el VASP, y ningún otro cliente los ve. Consulta [Diligencia debida de contrapartes](#diligencia-debida-de-contrapartes) para saber qué significa cada uno, y condiciona tus decisiones con los [campos de regla de contraparte](#campos-de-regla-y-presets) en lugar de crear bifurcaciones en tu código con ellos. Los miembros de la red de Didit no reciben puntuación: `dd_status` es `COMPLETED`, `dd_score` es `null`, `risk_level` está vacío y el desglose está vacío.

### Rutas

`routes` enumera las formas en que tu aplicación puede entregar al VASP, en el orden en que las prueba la secuencia de enrutamiento, y `reachable` es `true` cuando al menos una está `available`:

* `TRP` cuando la entrada tiene un endpoint TRP que el directorio verificó.
* `GTR`, `TRUST`, `VERIFYVASP`, `SYGNA` cuando una red registra al VASP con un código. La ruta está `available` solo cuando tu aplicación puede enviar hoy por esa red (`via: own_membership` para tu propia membresía conectada, `via: didit_membership` para la de Didit). En caso contrario está `unavailable` con `reason: no_membership` o `reason: network_switched_off`, y nunca se muestra como una forma de llegar al VASP. Las membresías de red propias de Didit aún no están activas, por lo que hoy una ruta de red solo está disponible mediante una membresía que hayas conectado en el Marketplace.
* `EMAIL` cuando existe un contacto de cumplimiento para la entrada.
* `INTERNAL` para un miembro de la red de Didit.

Un registro de `TRISA` aparece en `networks` e indica quién es el VASP en TRISA, pero Didit no tiene un canal TRISA, así que nunca es una ruta.

Una aplicación de sandbox solo envía al [VASP de prueba de Didit](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md), por lo que no tiene disponible ninguna ruta del directorio: todas las rutas están `unavailable` con `reason: sandbox_application`, todas las filas tienen `reachable: false` y `reachable=true` no devuelve filas.

### Marcas y sus entidades

Una marca que opera a través de varias entidades reguladas es una sola fila cuyas `entities` son las entidades jurídicas que reciben sus transferencias; una fila de entidad apunta a su marca en `umbrella`. Una transferencia que nombra la marca va a una de sus entidades, elegida entre todas ellas: la de la jurisdicción indicada en `beneficiary_data.counterparty_vasp_jurisdiction`; si no, la entidad que la [atribución de análisis de blockchain](#atribución-mediante-análisis-de-blockchain) vinculó a la wallet de destino; si no, la única entidad de la marca cuando no se indica ninguna jurisdicción. Solo entonces esa entidad debe ser alcanzable; si no lo es, la transferencia nunca se envía a otra entidad ni a la marca en su lugar. Cuando ninguna entidad encaja (dos encajan por igual, o se indica una jurisdicción en la que no está ninguna), se usa la ruta propia de la marca y, si no la tiene, la transferencia queda en `COUNTERPARTY_VASP_NOT_FOUND`. Qué entidad jurídica recibe los datos del ordenante nunca se adivina, ni se decide según qué entidad tenga un contacto.

Varias entradas con el mismo nombre, como empresas de un grupo que comparten un nombre comercial, se distinguen con la misma regla: la de la jurisdicción indicada o, si no, la que la atribución de análisis de blockchain vinculó. Cuando ninguna de las dos elige una, no se usa ninguna, y se considera que los datos no nombran ninguna entrada del directorio.

### Contactos

`contacts` son las direcciones a las que envía el canal `EMAIL`. Los contactos `scope: platform` sirven a todos los clientes de Didit: Didit los selecciona (`source: staff`), o una dirección de uno de los dominios propios del VASP respondió a una solicitud a través de su enlace de respuesta (`source: learned`). Los contactos `scope: application` son privados de tu aplicación: los que añades tú (`source: application`) y una dirección fuera de los dominios propios del VASP que respondió a una de tus solicitudes (`source: learned`). Una transferencia envía un correo primero al contacto propio de tu aplicación, luego a un contacto de plataforma que ya haya respondido antes (`verified_at` definido) y después a los demás.

Gestiona los contactos propios de tu aplicación con la API de contactos de contrapartes:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/counterparty-contacts/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"counterparty": "0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91", "email": "compliance@counterparty.example", "name": "Compliance desk"}'
```

* `GET /v3/travel-rule/counterparty-contacts/` enumera todos los contactos a los que tu aplicación puede enviar, incluidos los contactos de plataforma y los rebotados, del más reciente al más antiguo, paginados con `limit` y `offset`. Filtra con `?counterparty=` y el `id` de una entrada del directorio; un valor que no sea un UUID responde `400`.
* `POST` añade un contacto privado (`counterparty`, `email`, `name` opcional) y responde `201`. Si añades una dirección que la entrada ya tiene entre tus propios contactos, se devuelve ese contacto. Una entrada desconocida responde `400` (`"No directory entry with this id."`).
* `DELETE /v3/travel-rule/counterparty-contacts/{contact_uuid}/` elimina uno de tus propios contactos (`204`). Los contactos de plataforma no se pueden eliminar y responden `404`.

Un contacto que rebotó o presentó una queja tiene `is_invalid: true`, con `invalid_reason` (`hard_bounce`, `soft_bounce`, `spam_complaint` o `suppressed`), `invalid_detail` y `invalid_at`, y el canal `EMAIL` lo omite. `created_by` está vacío en los contactos de la plataforma y en los contactos que añadió una clave de API.

### Cómo se incorporan las entradas al directorio

* El registro provisional MiCA de proveedores de servicios de criptoactivos de ESMA, que se lee cada semana: el nombre, el LEI y el estado miembro de origen de cada proveedor.
* El directorio público de TRISA, que se lee cada semana: quién es cada miembro, su país y su inscripción en TRISA. Una inscripción que el directorio deja de mostrar durante tres semanas se elimina.
* El registro global de LEI completa el LEI, otros nombres legales y el país de una entrada, y encuentra el LEI de una entrada a partir de su nombre legal exacto en su país.
* La [atribución de análisis de blockchain](#atribución-mediante-análisis-de-blockchain) añade o asocia el VASP propietario de una wallet de destino y conserva el nombre atribuido como alias.
* El equipo de Didit revisa y mantiene las entradas: identificadores de enrutamiento e inscripciones en redes que ha verificado, contactos de cumplimiento, alias, marcas y sus entidades, duplicados fusionados y entradas ocultas.

Los datos que un cliente informa sobre una contraparte, como un `originating_vasp` entrante o un Travel Address, permanecen en la transferencia de ese cliente y nunca modifican una entrada compartida. Las entradas se asocian primero por LEI y después por nombre exacto o alias, y se enriquecen en lugar de duplicarse.

### La red de Didit

Tu perfil de VASP es miembro de la red de Didit, de modo que otros clientes de Didit lo encuentran en el directorio y en el selector de VASP del usuario final, solo mientras se cumplan todas estas condiciones:

* tu aplicación está en producción (no en sandbox) y Travel Rule está activada;
* `is_discoverable` es `true` y `legal_name` está definido;
* `compliance_email` está definido y confirmado: envía la confirmación con `POST /v3/travel-rule/settings/compliance-email/confirmation/` y abre el enlace que recibes por correo. Cambiar la dirección requiere una nueva confirmación;
* Didit no ha marcado la aplicación como de prueba, de demostración o interna.

El propio canal `INTERNAL` entrega a una wallet cuya titularidad has demostrado, como se describe en [Enviar una transferencia](#enviar-una-transferencia): requiere que tu aplicación esté en producción, que Travel Rule esté activada y `is_discoverable`, pero no el resto de la lista.

`GET /v3/travel-rule/settings/` devuelve `didit_network`: `listed`, `compliance_email_confirmed` y, en `missing`, cada condición que aún no se cumple (`travel_rule_off`, `sandbox_application`, `not_discoverable`, `legal_name_missing`, `compliance_email_missing`, `compliance_email_unconfirmed`, `excluded_by_staff`, `internal_organization`).

### Identificadores de enrutamiento

El enrutamiento saliente consulta una entrada del directorio siempre que tu transferencia identifica a la contraparte mediante `counterparty_vasp_lei` o `counterparty_vasp_name` (un alias también sirve). Una entrada incluye un identificador por cada red en la que se puede contactar, un endpoint TRP verificado y sus contactos de cumplimiento, y `routes` muestra cuáles de ellos puede usar tu aplicación. Siempre puedes omitir el directorio en una transferencia concreta pasando los campos explícitos de [Campos de resolución de la contraparte](#campos-de-resolución-de-la-contraparte).

## Diligencia debida de contrapartes

Antes de que los fondos de tus clientes lleguen a otro VASP, necesitas saber quién es ese VASP y si lo aceptas. La diligencia debida sobre una contraparte tiene dos capas:

* **La evaluación compartida.** Cada entrada del directorio incluye una puntuación de diligencia debida, su nivel de riesgo, un estado de capacidad de respuesta y un informe de comprobaciones esenciales. Didit los calcula a partir de los datos propios de la plataforma, por lo que todos los clientes ven los mismos valores.
* **Tus propios registros.** Tu decisión sobre el VASP, tu análisis de sanciones y medios adversos sobre él, y los cuestionarios de diligencia debida que intercambiaste con él pertenecen únicamente a tu aplicación. Ningún otro cliente los ve nunca, y nunca modifican la entrada compartida.

Tus propios registros funcionan igual para una entrada del directorio que para un miembro de la [red de Didit](#la-red-de-didit): identifícalos por el `id` que muestra el [directorio](#directorio).

| Endpoint | Qué hace |
| - | - |
| `GET` / `PUT` / `DELETE /v3/travel-rule/vasps/{vasp_id}/decision/` | Consulta, establece o elimina [tu decisión](#tu-decisión-sobre-una-contraparte) sobre la contraparte. |
| `GET` / `POST /v3/travel-rule/vasps/{vasp_id}/screening/` | Consulta tu [análisis de la contraparte](#análisis-de-la-contraparte) más reciente o ejecuta uno. |
| `GET` / `POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/` | Lista tus [cuestionarios de diligencia debida](#cuestionario-de-diligencia-debida) con la contraparte o envía uno. |
| `GET /v3/travel-rule/transfers/?counterparty={vasp_id}` | Tus [transferencias con esa contraparte](#transferencias-con-una-contraparte). |

### Puntuación y nivel de riesgo

`dd_score` va de 0 a 100 y **cuanto más alta, más segura**. Cada resultado lo indica en `dd_score_semantic`, que siempre es `higher_is_safer`. `risk_level` es la franja en la que cae la puntuación:

| `risk_level` | `dd_score` |
| - | - |
| `LOW` | 70 o más |
| `MEDIUM` | De 40 a 69 |
| `HIGH` | Menos de 40 |

La puntuación es la suma de siete componentes. `dd_score_breakdown` muestra cada uno como `{points, max, reason, detail}`: `max` es el peso del componente, `reason` un código legible por máquina que puedes traducir y `detail` una explicación de una línea en inglés.

| Componente | Peso | Cómo puntúa | Códigos `reason` |
| - | - | - | - |
| `jurisdiction` | 25 | Completo cuando el país de la entrada no está en la lista predeterminada de jurisdicciones de alto riesgo (`IRN`, `PRK`, `SYR`, `AFG`, `RUS`, `MMR`), nada cuando sí lo está y la mitad cuando el país es desconocido. | `jurisdiction_not_high_risk`, `jurisdiction_high_risk`, `jurisdiction_unknown` |
| `verification` | 15 | El estado de verificación de la entrada según Didit (`dd_status`): completo para `COMPLETED`, la mitad para `IN_PROGRESS`, un cuarto para `NOT_STARTED` y nada para `REJECTED`. | `dd_status_completed`, `dd_status_in_progress`, `dd_status_not_started`, `dd_status_rejected` |
| `protocol` | 15 | Completo cuando una vía de protocolo nativa llega a la entrada (un endpoint TRP o la vía `INTERNAL`), el 40 por ciento cuando solo llega la alternativa por correo electrónico y nada si no hay ninguna vía accesible. | `native_rail`, `email_only`, `no_rail` |
| `lei` | 10 | Completo con un LEI válido registrado, nada sin él. | `lei_valid`, `lei_missing` |
| `history` | 10 | La proporción de intercambios resueltos de la entrada que tuvieron éxito, la mitad si no hay ninguno. | `history`, `no_history` |
| `essentials` | 15 | La proporción de [comprobaciones esenciales](#comprobaciones-esenciales) resueltas que se superan, la mitad mientras no se haya resuelto ninguna. | `essential_checks`, `no_essential_checks` |
| `responsiveness` | 10 | Completo para `RESPONSIVE`, nada para `UNRESPONSIVE` y la mitad para `UNKNOWN`. Consulta [Capacidad de respuesta](#capacidad-de-respuesta). | `responsive`, `unresponsive`, `responsiveness_unknown` |

Los puntos se redondean a un decimal y el total a un número entero. `history` lee las mismas solicitudes que la [capacidad de respuesta](#capacidad-de-respuesta), sin ventana temporal: un intercambio `COMPLETED` o `FINISHED` es un éxito, y un intercambio `EXPIRED`, `COUNTERPARTY_MISMATCHED_DATA` o `COUNTERPARTY_VASP_GENERAL_DECLINE` es un fallo. Una cancelación es un acto propio del remitente y nunca cuenta.

Didit vuelve a calcular la evaluación cuando un intercambio con la entrada se completa, finaliza, expira, presenta discrepancias o es rechazado, cuando actualiza o revisa la entrada, y para cada entrada en la actualización semanal del directorio. `dd_assessed_at` indica cuándo se ejecutó por última vez; una entrada que aún no se ha evaluado no tiene `dd_assessed_at`, tiene un `dd_score` de `0` y un `risk_level` vacío, así que consulta `risk_level` en lugar de la puntuación sin procesar. Los miembros de la red de Didit no se puntúan: su `dd_score` es `null`, su `risk_level` está vacío y su `dd_score_breakdown` está vacío.

### Comprobaciones esenciales

`essential_checks` es un informe breve sobre cuatro comprobaciones que Didit ejecuta sobre cada entrada del directorio, solo a partir de las fuentes verificadas de la plataforma y nunca a partir de datos que haya reportado un cliente:

| `id` de la comprobación | Se supera cuando |
| - | - |
| `registration` | Un registro oficial incluye al VASP: el registro provisional MiCA de la UE de proveedores de servicios de criptoactivos, el directorio público de TRISA o el registro global de LEI con un LEI emitido. |
| `licence` | El registro MiCA recoge una autorización del VASP que no ha finalizado. |
| `domain` | El dominio de la entrada coincide con su endpoint TRP o con el sitio web que indica su registro. |
| `lei` | El registro LEI de la entrada está activo y emitido, y su denominación legal y su país coinciden con la entrada. |

Cada comprobación de `checks` informa de su `status` (`pass`, `fail` o `unknown` cuando ninguna fuente registrada puede resolverla), un `reason` legible por máquina y un `detail` de una línea en inglés. `passed`, `failed`, `unknown` y `total` las cuentan, `level` es `essential` y `checked_at` indica cuándo se generó el informe. El componente `essentials` puntúa la proporción de comprobaciones resueltas que se superan, por lo que una comprobación `unknown` no cuenta ni a favor ni en contra de la entrada. El informe está vacío hasta que la actualización semanal del directorio comprueba una entrada por primera vez, y siempre está vacío para un miembro de la red de Didit.

### Capacidad de respuesta

`responsiveness` indica si el VASP responde a las solicitudes de Travel Rule:

```json theme={null}
{ "status": "UNRESPONSIVE", "answered": 0, "total": 6, "computed_at": "2026-10-12T09:30:00Z" }
```

`total` cuenta las solicitudes que los clientes de Didit iniciaron hacia el VASP en los últimos 90 días cuyo resultado está resuelto, y `answered` las que respondió:

* **Se cuentan:** las solicitudes enviadas por una vía de red o de protocolo, y las solicitudes enviadas por correo electrónico a una dirección compartida, que es la dirección de cumplimiento de la entrada o un contacto de la plataforma.
* **Nunca se cuentan:** una solicitud enviada por correo electrónico a una dirección que escribió un cliente, o al contacto privado de un cliente. Ese intercambio permanece en el historial de transferencias del propio cliente y nunca etiqueta al VASP para los demás.
* **Respondidas:** `COMPLETED`, `FINISHED`, `COUNTERPARTY_VASP_GENERAL_DECLINE` o `COUNTERPARTY_MISMATCHED_DATA`. Un rechazo o una discrepancia es una respuesta: el VASP intervino.
* **Sin respuesta:** `EXPIRED`.
* **Ninguna de las dos:** cualquier otro estado. Una solicitud `CANCELLED` es un acto propio del remitente, `COUNTERPARTY_VASP_NOT_REACHABLE` puede ser un fallo del lado del remitente y una solicitud que sigue en curso aún no está resuelta.

| `status` | Cuándo |
| - | - |
| `UNKNOWN` | Menos de 5 solicitudes resueltas en la ventana, de modo que una sola solicitud expirada nunca etiqueta a un VASP. |
| `UNRESPONSIVE` | El VASP respondió menos del 10 por ciento de sus solicitudes resueltas. |
| `RESPONSIVE` | En cualquier otro caso. |

Los miembros de la red de Didit responden dentro de Didit y siempre muestran `UNKNOWN` con recuentos a cero. Actúa ante una contraparte que no responde con la [política de no respuesta](#políticas-de-periodo-de-transición-y-de-falta-de-respuesta) o con el [preset](#campos-de-regla-y-presets) `travel-rule-counterparty-unresponsive`.

### Tu decisión sobre una contraparte

Registra el dictamen de tu equipo de cumplimiento sobre una contraparte con `PUT /v3/travel-rule/vasps/{vasp_id}/decision/`:

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/decision/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"decision": "BLOCKED", "reason": "Unlicensed in its home jurisdiction"}'
```

```json theme={null}
{
  "decision": {
    "decision": "BLOCKED",
    "reason": "Unlicensed in its home jurisdiction",
    "decided_by": "",
    "updated_at": "2026-10-14T10:05:00Z",
    "inherited_from": null
  }
}
```

| `decision` | Significado | Preset que actúa sobre ella |
| - | - | - |
| `APPROVED` | Tu equipo aprobó la contraparte. | Ninguno |
| `RESTRICTED` | Las transferencias hacia ella pueden seguir adelante tras una revisión. | `travel-rule-counterparty-restricted` las retiene para revisión. |
| `BLOCKED` | Tu equipo rechazó la contraparte. | `travel-rule-counterparty-blocked` las rechaza. |

* La decisión es privada de tu aplicación: ningún otro cliente la ve y nunca modifica la entrada compartida.
* Una decisión no cambia nada por sí sola y nunca cambia cómo se enruta una transferencia. Llega a tus transacciones a través del [campo de regla](#campos-de-regla-y-presets) `counterparty_dd_status`: instala los presets o escribe tu propia regla sobre él.
* Una decisión sobre una marca cubre cada una de sus [entidades](#marcas-y-sus-entidades) que no tenga una decisión propia, y la entidad muestra la marca en `inherited_from`. Una decisión sobre la entidad prevalece sobre la de la marca para esa entidad.
* `GET` devuelve la decisión que se aplica, o `{"decision": null}`. `DELETE` elimina tu propia decisión y devuelve lo que se aplica a continuación: la decisión de la marca para una entidad o, en otro caso, `null`. Responde `404` cuando tu aplicación no tiene una decisión propia sobre la contraparte.
* `reason` es opcional, admite hasta 255 caracteres y cada `PUT` lo reemplaza. `decided_by` es el usuario de la consola que tomó o modificó por última vez la decisión, y queda vacío cuando lo hizo una clave de API.

### Análisis de la contraparte

El análisis de la contraparte comprueba el propio VASP de la contraparte, como empresa, frente a sanciones y medios adversos. Es **opcional y se factura**: actívalo con `counterparty_screening_enabled` en tu [configuración](#configuración). Mientras está desactivado, no se analiza ni se factura nada.

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/screening/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"refresh": false}'
```

```json theme={null}
{
  "outcome": "screened",
  "screening": {
    "id": "7a1d2c3b-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
    "status": "In Review",
    "total_hits": 2,
    "score": 85.0,
    "screened_at": "2026-10-14T09:58:00Z",
    "fresh": true,
    "flagged": true
  }
}
```

* **Facturación.** Cada nuevo análisis cuesta el [precio](https://docs.didit.me/es/getting-started/pricing.md) de Company AML Screening de tu organización. `GET /v3/travel-rule/vasps/{vasp_id}/screening/` devuelve ese `price`, `fresh_days` y si el análisis está activado (`enabled`), sin coste. Un análisis de menos de 30 días se considera reciente: `POST` lo devuelve de nuevo con `200` y `outcome: reused` y no factura nada, salvo que envíes `refresh: true`. Un nuevo análisis responde `201` con `outcome: screened`. Las aplicaciones de sandbox nunca se analizan ni se facturan.
* **Análisis automático.** Con el análisis activado, Didit también analiza la contraparte a la que llega un intercambio saliente cuando este comienza, antes de que tus reglas evalúen la transacción, con la misma reutilización y facturación. Un rechazo o un fallo en ese punto nunca hace fallar la transferencia.
* **Resultado.** `status` es `Approved` cuando ninguna posible coincidencia requiere atención, y `In Review` o `Declined` ante una posible coincidencia en sanciones o medios adversos. `flagged` es `true` mientras un análisis reciente está en `In Review` o `Declined`.
* **Efecto.** Mientras tu último análisis de una contraparte esté marcado y el análisis siga activado, `counterparty_risk_level` es `HIGH` en tus reglas, de modo que el preset `travel-rule-counterparty-high-risk`, una vez instalado, retiene sus transferencias. El `risk_level` compartido del directorio no cambia.
* **Privacidad.** El análisis es privado de tu aplicación: ningún otro cliente lo ve y nunca modifica la entrada compartida. El directorio muestra el más reciente como `entity_screening`.
* **Rechazos.** `409` cuando el análisis está desactivado, para una aplicación de sandbox o mientras ya se está ejecutando un análisis de la misma contraparte. `403` con `code: insufficient_credits` cuando tu saldo no cubre el precio. `502` cuando no se pudo completar el análisis. Ninguno de ellos factura nada.

### Cuestionario de diligencia debida

Solicita a una contraparte sus respuestas de diligencia debida con el cuestionario estándar de Didit. `POST /v3/travel-rule/vasps/{vasp_id}/questionnaires/` lo envía por correo electrónico a una dirección de cumplimiento registrada de la contraparte, con un enlace de un solo uso a una página de respuesta:

```bash theme={null}
curl -X POST https://verification.didit.me/v3/travel-rule/vasps/0d6f3c2a-6a1e-4c55-9a39-1f2b0c7d8e91/questionnaires/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sent_to": "travelrule@counterparty.example"}'
```

```json theme={null}
{
  "id": "3f9e8d7c-6b5a-4c3d-9e2f-1a0b9c8d7e6f",
  "status": "SENT",
  "form_version": "1",
  "sent_to": "travelrule@counterparty.example",
  "sent_at": "2026-10-14T10:00:00Z",
  "expires_at": "2026-11-13T10:00:00Z",
  "answered_at": null,
  "valid_until": null,
  "current": false,
  "answers": {}
}
```

* **Adónde se envía.** `sent_to` debe ser una dirección de cumplimiento registrada: para una entrada del directorio, su dirección de cumplimiento o un contacto que tu aplicación ve en `contacts`; para un miembro de la red de Didit, su correo de cumplimiento confirmado. Omítelo para usar la dirección a la que se envía un correo de Travel Rule a la contraparte: primero tu propio contacto, luego un contacto de la plataforma y, por último, la dirección de cumplimiento de la entrada. Didit nunca envía el cuestionario a ningún otro lugar y responde `400` cuando la contraparte no tiene ninguna dirección de cumplimiento registrada.
* **Respuesta.** El enlace abre `/v3/travel-rule/questionnaires/{token}/`, una página para una persona de la contraparte que no requiere cuenta ni clave de API. Esa persona responde a todas las preguntas, con hasta 2,000 caracteres cada una (`N/A` cuando alguna no aplique), y envía una sola vez. Una contraparte también puede enviar `{"answers": {"<question id>": "<answer>"}}` al mismo enlace. Un enlace ya usado, reemplazado o cuyo plazo ha vencido muestra en su lugar una página de expiración. El correo y la página están traducidos; las preguntas en sí están siempre en inglés, para que su significado nunca cambie entre idiomas.
* **Plazos.** La contraparte tiene 30 días para responder (`expires_at`). Las respuestas siguen vigentes durante 365 días (`valid_until`), y `current` es `true` hasta entonces. Un cuestionario sin responder cuyo plazo ha vencido, y las respuestas que han superado su validez, pasan a `EXPIRED`.
* **Un cuestionario abierto por contraparte.** Un nuevo envío reemplaza tu cuestionario anterior sin responder a la misma contraparte: pasa a `EXPIRED` y su enlace deja de funcionar. Se puede enviar un correo por minuto a una dirección; un envío más rápido responde `429`.
* **Lectura de respuestas.** `GET /v3/travel-rule/vasps/{vasp_id}/questionnaires/` enumera tus cuestionarios con la contraparte, del más reciente al más antiguo, con `answers` indexadas por id de pregunta una vez respondidos. El directorio los muestra como `questionnaires`. Son privados de tu aplicación.

La versión `1` del formulario incluye estas doce preguntas:

| ID de la pregunta | Pregunta |
| - | - |
| `legal_name` | Denominación legal de la entidad y jurisdicción de constitución. |
| `licensing` | Licencias o registros que tienes para servicios de activos virtuales: regulador, número de licencia y estado en cada jurisdicción. |
| `jurisdictions` | Jurisdicciones en las que operas y aquellas en las que estás excluido o tienes restricciones. |
| `aml_program` | Resumen de tu programa AML/CFT: políticas, procedimientos y fecha de la última auditoría o revisión independiente. |
| `compliance_officer` | Nombre y rol de tu responsable de cumplimiento, y cómo contactarlo. |
| `sanctions_screening` | Cómo analizas a clientes y contrapartes frente a sanciones y medios adversos: proveedor o listas, frecuencia y escalado. |
| `transaction_monitoring` | Cómo monitorizas las transacciones para detectar actividad sospechosa: herramientas, umbrales y práctica de reporte. |
| `travel_rule` | Cómo cumples la Travel Rule: protocolos y redes que usas, y tu tiempo de respuesta habitual a una solicitud. |
| `custody` | Sistema de custodia de los activos de los clientes: custodio cualificado, seguro y segregación. |
| `ownership` | Beneficiarios finales con un 25 por ciento o más, y cualquier entidad matriz o paraguas. |
| `record_keeping` | Práctica de conservación de registros y periodo de retención de los datos de la Travel Rule y de las transacciones. |
| `data_protection` | Cómo proteges los datos personales compartidos con fines de cumplimiento y dónde se almacenan. |

### Transferencias con una contraparte

[`GET /v3/travel-rule/transfers/?counterparty={vasp_id}`](https://docs.didit.me/es/management-api/travel-rule/list-transfers) lista las transferencias de la Travel Rule de tu aplicación con una contraparte, de la más reciente a la más antigua, según el `id` que muestra el directorio: tus transferencias cuya contraparte es esa entrada del directorio, o tus intercambios `INTERNAL` con ese miembro de la red de Didit. Un valor que no sea un id válido responde `400`.
Cada fila incluye `reason` justo después de `status`: el propio [`reason`](#por-qué-una-transferencia-está-bloqueada) de la transferencia, de modo que la lista distingue un correo de cumplimiento rebotado de una contraparte sin ruta sin tener que abrir cada transferencia.

### Políticas de periodo de transición y de falta de respuesta

Cuando una transferencia expira (transcurrió `confirmation_timeout_hours` mientras estaba en `AWAITING_COUNTERPARTY`), `timeout_outcome` decide qué ocurre con su transacción. Dos opciones de configuración te permiten tratar de forma distinta dos motivos habituales de expiración:

| Opción | Se aplica cuando la contraparte es una entrada del directorio que |
| - | - |
| `sunrise_policy` | Está en una jurisdicción incluida en `sunrise_jurisdictions`: un país que todavía no aplica la Travel Rule, por lo que el VASP no está obligado a responder. |
| `non_responsive_policy` | Tiene `responsiveness.status` `UNRESPONSIVE`. |

Ambas admiten `HOLD`, `REJECT` o `PROCEED`, con el mismo significado que en `timeout_outcome`, o una cadena vacía para seguir `timeout_outcome`. Ambas están vacías por defecto, así que nada cambia hasta que configures una:

```bash theme={null}
curl -X PUT https://verification.didit.me/v3/travel-rule/settings/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sunrise_policy": "PROCEED", "non_responsive_policy": "HOLD"}'
```

La primera de estas que se aplique decide el resultado:

1. `sunrise_policy`, cuando está configurada y la jurisdicción de la contraparte está en `sunrise_jurisdictions`.
2. `non_responsive_policy`, cuando está configurada y la contraparte está en `UNRESPONSIVE`.
3. `timeout_outcome` en cualquier otro caso, incluida una transferencia a un miembro de la red de Didit o a una contraparte sin entrada en el directorio.

`sunrise_jurisdictions` es de solo lectura y actualmente es `["CO", "KH", "VN"]`. Solo estos países se consideran en periodo de transición: cualquier otra jurisdicción, así como una vacía o desconocida, sigue `timeout_outcome`, por lo que a una contraparte nunca se le aplica tu política de periodo de transición por accidente. El historial de la transferencia expirada indica el resultado que se aplicó, por ejemplo `sunrise_policy=PROCEED (counterparty jurisdiction CO does not enforce the Travel Rule yet)`. Tus reglas se siguen ejecutando después de la expiración, así que una regla como `tr_eu_expired_review` del EU TFR puede seguir enviando la transacción a revisión con `PROCEED`.

### Campos de regla y presets

Cuatro campos de [regla](https://docs.didit.me/es/transaction-monitoring/rules.md) contienen lo que tu aplicación sabe sobre la contraparte a la que llegó el intercambio de la Travel Rule de una transacción: su entrada del directorio o, en un intercambio `INTERNAL`, el cliente de Didit que lo recibió. Cada campo está vacío cuando el intercambio no llegó a ninguna contraparte conocida.

| Campo | Valor |
| - | - |
| `counterparty_dd_status` | Tu [decisión](#tu-decisión-sobre-una-contraparte): `APPROVED`, `RESTRICTED` o `BLOCKED`; una entidad sigue la de su marca. Vacío si no tomaste ninguna. Nunca la decisión de otro cliente. |
| `counterparty_risk_level` | El `risk_level` de la entrada (`LOW`, `MEDIUM` o `HIGH`), o `HIGH` mientras tu propio [análisis](#análisis-de-la-contraparte) de la contraparte esté marcado. Vacío para una entrada aún no evaluada y para un miembro de la red de Didit, salvo que tu análisis de este esté marcado. |
| `counterparty_jurisdiction` | El país de la contraparte, según la entrada del directorio o el perfil del miembro de la red de Didit. Se comparan tanto los códigos ISO-2 como ISO-3, igual que en los demás campos de país. |
| `counterparty_responsiveness` | El `responsiveness.status` de la entrada: `RESPONSIVE`, `UNRESPONSIVE` o `UNKNOWN`. Vacío para un miembro de la red de Didit. |

Cinco presets del paquete `travel_rule` actúan sobre ellos. Instálalos desde **Transactions → Rules → Library** en la Business Console o con la [API de la biblioteca de reglas](https://docs.didit.me/es/management-api/transactions/rules-install.md):

| `library_key` | Disparador | Acción por defecto |
| - | - | - |
| `travel-rule-counterparty-blocked` | `counterparty_dd_status` es `BLOCKED` | +90 de puntuación, `DECLINED` |
| `travel-rule-counterparty-restricted` | `counterparty_dd_status` es `RESTRICTED` | +50 de puntuación, `IN_REVIEW` |
| `travel-rule-counterparty-high-risk` | `counterparty_risk_level` es `HIGH` | +40 de puntuación, `IN_REVIEW` |
| `travel-rule-counterparty-high-risk-jurisdiction` | `counterparty_jurisdiction` está en la lista de alto riesgo por defecto (`IRN`, `PRK`, `SYR`, `AFG`, `RUS`, `MMR`) | +60 de puntuación, `IN_REVIEW` |
| `travel-rule-counterparty-unresponsive` | `counterparty_responsiveness` es `UNRESPONSIVE` | +30 de puntuación, `IN_REVIEW` |

Los cinco se aplican solo a transacciones de la Travel Rule.

## Webhooks

Suscribe un destino a `travel_rule.status.updated` para recibir una notificación en cada cambio de estado de cada transferencia de tu aplicación, ya sea saliente o entrante, incluidos los tramos del rail `INTERNAL`.
El enrutamiento se ejecuta después de que se devuelve la respuesta de creación de la transacción, así que resultados como `COUNTERPARTY_VASP_NOT_FOUND`, `COUNTERPARTY_VASP_NOT_REACHABLE` o un intercambio `INTERNAL` que se liquida al instante te llegan a través de este evento y no en la respuesta de creación.

```json theme={null}
{
  "event_id": "9c0c8b8a-1111-4222-9333-666666666666",
  "webhook_type": "travel_rule.status.updated",
  "timestamp": 1774970000,
  "created_at": 1774970000,
  "application_id": "11111111-2222-3333-4444-555555555555",
  "environment": "live",
  "transaction_id": "22222222-3333-4444-5555-666666666666",
  "txn_id": "trv-2026-07-05-001",
  "travel_rule_status": "COMPLETED",
  "rail": "INTERNAL",
  "direction": "OUTBOUND"
}
```

`rail` está vacío hasta que se selecciona un rail.
Para una misma transacción, Didit envía `travel_rule.status.updated` después de `transaction.created`: cuando Didit crea la transacción (tu `POST /v3/transactions/`, un registro sunrise, una consulta `TRP` entrante o el tramo entrante del rail `INTERNAL`), envía primero `transaction.created`.
Cada evento se entrega y se reintenta por separado, así que un `transaction.created` que necesitó un reintento puede llegar después de un evento de estado: identifica las transacciones en tu handler por `transaction_id` y consulta la transacción cuando un evento de estado haga referencia a una que aún no hayas visto.
Una transferencia enviada a través de `TRUST` no recibe ningún evento `COMPLETED`: TRUST no devuelve nada que Didit pueda leer, así que, salvo que el envío falle o lo canceles, su último evento es `EXPIRED`. A través de `GTR`, `VERIFYVASP` y `SYGNA`, el evento refleja la respuesta que Didit lee de la red.
Las aplicaciones de sandbox también envían este evento, con `"environment": "sandbox"`; una transferencia a la que respondió el [Didit Test VASP](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) incluye `rail: "TEST_VASP"`, `test_vasp: true` y `test_vasp_scenario`.

Consulta la [guía de webhooks](https://docs.didit.me/es/integration/webhooks.md#tipos-de-eventos) para ver el catálogo completo de eventos, la verificación de firma y la política de reintentos.

## Precios

La tarifa de Travel Rule es de **\$0.02 por cada intercambio saliente que se inicia**, y se cobra una sola vez al crear la transacción, sin importar cuántos cambios de estado tenga el intercambio después. Un `resend` nunca la vuelve a cobrar.

* Se aplica a una transacción `travelRule` saliente en una aplicación con Travel Rule activada, cuyo importe es igual o superior a tu `threshold_amount`, de modo que Didit inicia un intercambio gestionado para ella. Una transferencia a una wallet sin custodia, o a la wallet verificada de tu propio usuario, también cuenta: la prueba de propiedad es su intercambio.
* Cualquier otra transacción saliente que incluya datos de Travel Rule se factura como Análisis de transacciones estándar, que tu plan incluye hasta su [cupo mensual de transacciones](https://docs.didit.me/es/getting-started/pricing.md#monitorización-de-transacciones-kyt) y que cuesta \$0.001 por encima de él: una transferencia por debajo de tu umbral, un pago Lightning al que no se aplica la Travel Rule y una transferencia registrada de forma pasiva mientras Travel Rule está desactivada. Una transacción se factura en una de las dos líneas, nunca en ambas.
* Las transacciones `travelRule` entrantes no tienen tarifa de Travel Rule ni de monitorización: el tramo entrante que Didit crea en la aplicación del beneficiario a través del rail `INTERNAL`, las consultas `TRP` entrantes y los [registros posteriores al depósito](#registro-sunrise-posterior-al-depósito).
* Una aplicación que se unió a Travel Rule de forma gratuita no paga ninguna de las dos tarifas en las transacciones `travelRule` salientes hasta que activa la facturación saliente con `POST /v3/travel-rule/workspace/billing/`; la recepción sigue siendo gratuita.
* A las aplicaciones de sandbox nunca se les cobra.
* La tarifa de Travel Rule tiene un precio de lista de $0.02 y el Análisis de transacciones de $0.001 por encima de tu cupo. A cada transacción se le cobra el precio de la línea en la que se factura.
* Si en la misma transacción también se ejecuta el análisis AML de criptomonedas o de wallets (por ejemplo, un depósito entrante con `currency_kind: "crypto"` y la monitorización activada), se factura por separado a la tarifa estándar de Verificación y análisis de wallets; no está incluido en la tarifa de Travel Rule.
* El [análisis de contrapartes](#análisis-de-la-contraparte) es opcional y se factura por separado, al precio del Análisis AML de empresas por cada análisis; un análisis con menos de 30 días de antigüedad se reutiliza sin coste. Las decisiones, los cuestionarios y la evaluación de diligencia debida del directorio no tienen coste.

### Precio de la atribución

La [atribución mediante analítica de blockchain](#atribución-mediante-análisis-de-blockchain) requiere una consulta de la wallet al proveedor de analítica, y siempre obtienes el valor completo de esa consulta:

* **La monitorización de criptomonedas ya analizó la wallet en esta transacción**: se reutiliza el resultado almacenado. Una llamada de analítica, un cargo de Verificación y análisis de wallets (el que ya generó la monitorización de criptomonedas). La atribución no añade nada.
* **La monitorización de criptomonedas no se ejecutó**: Didit realiza una sola vez la llamada de analítica necesaria y te proporciona todo su valor: a la transacción se le cobra la tarifa estándar de Verificación y análisis de wallets (\$0.15 con la analítica gestionada por Didit) y, a cambio, recibe el resultado completo del análisis de criptomonedas (puntuación de riesgo, categoría de riesgo de la wallet, instantánea de la red), no solo el nombre del VASP. La partida de uso se marca con el disparador `travel_rule_attribution` para que el cargo sea explicable.
* **Clave de analítica propia**: se aplica la misma tarifa de plataforma que en la monitorización de criptomonedas con tu propia clave (\$0.02 por llamada). Tu proveedor te factura directamente la consulta subyacente.
* **Las consultas fallidas nunca se cobran**, los reenvíos reutilizan la atribución registrada sin una nueva llamada ni un nuevo cargo, y a las aplicaciones de sandbox nunca se les cobra.

Así, una transferencia saliente que necesitó atribución cuesta \$0.02 (Travel Rule) + un cargo de Verificación y análisis de wallets, y cuando ambos productos están activados, la llamada de analítica y su cargo se producen una sola vez.

## Paquete de reglas EU TFR

El paquete `travel_rule_eu_tfr` incluye cuatro reglas predefinidas, diseñadas específicamente para las obligaciones del TFR de la UE.
Como cualquier otro [paquete predefinido](https://docs.didit.me/es/transaction-monitoring/rules-library.md), actívalo desde la Business Console en **Transactions → Rules → Library**.

| Regla (`library_key`) | Disparador | Acción |
| - | - | - |
| `tr_eu_mismatch_hold` | El estado de la transferencia es `COUNTERPARTY_MISMATCHED_DATA` | `+50` de puntuación, la transacción pasa a `IN_REVIEW` |
| `tr_eu_unverified_selfhosted_review` | El estado de la transferencia es `UNCONFIRMED_OWNERSHIP` y el importe en la moneda predeterminada es de al menos `1000` | La transacción pasa a `IN_REVIEW` |
| `tr_eu_vasp_not_found_score` | El estado de la transferencia es `COUNTERPARTY_VASP_NOT_FOUND` | `+25` de puntuación, etiquetada como `travel-rule-sunrise` |
| `tr_eu_expired_review` | El estado de la transferencia es `EXPIRED` | La transacción pasa a `IN_REVIEW` |

Estas reglas se ejecutan en cada transición relevante (al crear la transferencia, al confirmarse la propiedad, al recibirse la respuesta del proceso de recogida de correo electrónico y durante el proceso de barrido de transferencias expiradas), de modo que una transferencia que nunca se resuelve sigue llegando a revisión de cumplimiento en lugar de liquidarse sin que nadie lo note.

## Por qué esto funciona mejor en una sola plataforma

El cumplimiento de la Travel Rule es un problema de identidad disfrazado de problema de pagos, y Didit ya tiene la identidad:

* **Datos verificados disponibles.** El sujeto de cada transferencia está vinculado mediante `vendor_data` al perfil KYC que Didit verificó durante el onboarding (OCR del documento, prueba de vida, coincidencia facial), así que puedes construir `originator_data` a partir de campos verificados en la misma plataforma.
  Para un usuario con una verificación KYC aprobada, Didit transmite la identidad verificada en lugar de los valores que escribiste (consulta [Datos verificados y procedencia](#datos-verificados-y-procedencia)).
* **Verificación biométrica reforzada para transferencias de riesgo.** Una [regla](https://docs.didit.me/es/transaction-monitoring/rules.md) puede retener cualquier transferencia de alto valor hasta que el usuario supere una nueva comprobación biométrica contra el rostro capturado durante el onboarding, la respuesta más sólida posible a la toma de control de cuentas en el momento del retiro. Consulta el [ejemplo práctico](https://docs.didit.me/es/transaction-monitoring/sdk-transaction-submission.md#ejemplo-biometría-reforzada-para-un-retiro-de-alto-valor).
* **Un único grafo de dispositivos.** Las transferencias enviadas mediante el SDK incluyen la misma información de dispositivo que las sesiones KYC, así que "dispositivo nuevo + importe alto + beneficiario nuevo" es una sola regla, no un join en un data warehouse.
* **Análisis, reglas, casos e intercambio en un solo lugar.** El análisis de wallets que identifica al VASP de la contraparte es el mismo análisis que ven tus reglas y tus analistas: un solo cargo, una sola consola, un solo registro de auditoría.
* **Precios publicados.** [\$0.02 por intercambio saliente](#precios), sin niveles por volumen y sin llamadas con el equipo de ventas.

## Preguntas frecuentes

### Cómo funciona el intercambio

> [accordion] ¿Didit ejecuta por sí mismo el intercambio entre VASP, o solo registra los datos de Travel Rule después de que otra red completa el handshake?
>
> Didit ejecuta el intercambio por sí mismo.
> Cuando envías una transferencia `travelRule`, Didit descubre la contraparte en tiempo real, envía los datos del ordenante y del beneficiario al VASP receptor por los canales que los transportan y marca la transferencia como `COMPLETED` solo cuando la contraparte la confirma: es un handshake gestionado, no un registro posterior a la liquidación.
> La respuesta de la contraparte se procesa en todos los canales excepto `TRUST`, que solo envía, por lo que una transferencia por ese canal expira en lugar de completarse. Por `GTR`, `VERIFYVASP` y `SYGNA`, Didit lee la respuesta de la red o consultándola cada 5 minutos, y ningún intercambio por estos canales se ha completado todavía con una red activa. Por `TRP`, una respuesta que la contraparte no da de inmediato necesita el host TRP público de Didit, que aún no está activo (consulta [Redes de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md)).
> Didit también conserva el registro completo y el estado de cumplimiento de cada intercambio (un [ciclo de vida](#ciclo-de-vida) de 13 estados, [webhooks](#webhooks) y un registro de auditoría).
> Si prefieres gestionar Travel Rule con tu propio proceso, Didit puede registrar los datos de forma pasiva como tu único sistema de registro (consulta más abajo la pregunta sobre el registro pasivo).
> Ambos modos están disponibles: el intercambio activo se ejecuta cuando estableces `is_enabled: true` en la [configuración](#configuración) (su valor predeterminado es `false`), y hasta entonces Didit registra los datos de forma pasiva.

> [accordion] ¿El intercambio es nativo de Didit o depende de un proveedor externo de interoperabilidad (Notabene, Sygna, VerifyVASP, TRP)?
>
> Es nativo. Didit ejecuta su propia implementación del Travel Rule Protocol (TRP), que se servirá en `trp.didit.me` cuando ese host público esté activo (todavía no responde, así que hoy las contrapartes no pueden contactarte por TRP), e implementa directamente los protocolos de las redes del sector: `GTR` (Global Travel Rule), `TRUST`, `VerifyVASP` y `Sygna Bridge` (implementado de forma nativa, incluidos los mensajes IVMS 101 cifrados con ECIES y las solicitudes de permiso firmadas de Sygna). Didit no revende una única capa de interoperabilidad de terceros. Para llegar a una contraparte que está en una red de membresía concreta hay que pasar necesariamente por esa red, ya que en Travel Rule no existe un canal universal único, pero el descubrimiento, el handshake, la verificación y el mantenimiento de registros los ejecuta Didit.
> Hoy cada canal de red requiere tu propia membresía, y `TRUST` solo envía: consulta [Descripción general](#descripción-general).

> [accordion] ¿Qué redes y protocolos de Travel Rule admite Didit?
>
> Se implementan de forma nativa y se intentan en estricto orden de prioridad: `INTERNAL` (ambos VASP en Didit), `TRP` (OpenVASP Travel Rule Protocol), `GTR`, `TRUST`, `VerifyVASP`, `Sygna Bridge` y una alternativa por `EMAIL` para contrapartes sin herramientas.
> Hoy los canales de red requieren tu propia membresía, `TRUST` solo envía y la recepción a través de una red aún no está activada: consulta [Redes de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md).
> CODE, TRISA, Notabene y Veriscope aparecen en el Marketplace de Didit como fichas de solicitud de acceso, todavía sin integración.
> Consulta [Cómo enruta Didit un intercambio](https://docs.didit.me/es/transaction-monitoring/travel-rule-interoperability.md#cómo-didit-enruta-transferencias-a-un-exchange) para ver la tabla de enrutamiento completa, y [Redes de Travel Rule](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md) para saber a quién llega cada una hoy.

> [accordion] ¿Qué red debo usar y necesito mis propias membresías?
>
> `TRP` es la base que recomendamos: no requiere una membresía compartida (compartir tu [travel address](#direcciones-de-viaje) permite que cualquier VASP que use TRP te contacte) y, cuando una contraparte solo se conoce por su dirección de wallet, la [atribución mediante análisis de blockchain](#atribución-mediante-análisis-de-blockchain) la enruta por TRP solo si la entrada del directorio atribuida ya tiene un endpoint TRP.
> En los envíos salientes, Didit envía por este canal los activos indicados en [Identificadores de activos TRP](#identificadores-de-activos-de-trp), y una contraparte que no responde de inmediato necesita el host TRP público de Didit, que aún no está activo.
> En cuanto a las redes de membresía, elige según dónde operan tus contrapartes: GTR ofrece una amplia cobertura global, TRUST está orientada a VASP de EE. UU. y VerifyVASP (que ahora también opera Sygna Bridge) tiene una gran cobertura en Asia.
> Sí, hoy necesitas tu propia membresía: Didit todavía no tiene una membresía de plataforma en estas redes y está en proceso de incorporarse como proveedor.
> Conecta tu membresía en **Marketplace**; no quedas atado a una sola red.
> Recuerda que `TRUST` solo envía, por lo que una transferencia por ese canal no se completa, y que ningún intercambio a través de una red se ha completado todavía contra una red real.

> [accordion] ¿Cómo encuentra Didit el VASP de la contraparte cuando solo tengo una dirección de wallet?
>
> Mediante una cadena de resolución: otro cliente de Didit que haya demostrado el control de la wallet (el canal `INTERNAL`), tu propia [libreta de direcciones de wallets](#libreta-de-direcciones-de-wallets) para una travel address guardada, después los canales de protocolo y de red y, por último, la [atribución mediante análisis de blockchain](#atribución-mediante-análisis-de-blockchain).
> Si la transferencia solo incluye una wallet de destino, Didit la resuelve con datos de análisis de blockchain para atribuir el exchange o servicio de custodia de la contraparte y lo cataloga en el [directorio de VASP](#directorio).
> Después, la transferencia se enruta automáticamente solo si esa entrada del directorio ya tiene una ruta, como un endpoint `TRP`; de lo contrario, termina en `COUNTERPARTY_VASP_NOT_FOUND` con el nombre de la contraparte registrado, y puedes volver a enviarla cuando exista una ruta, por ejemplo, después de guardar la `travel_address` de la contraparte en la entrada de tu libreta de direcciones para esa wallet (para los activos indicados en [Identificadores de activos TRP](#identificadores-de-activos-de-trp)).

### Precios y licencias

> [accordion] ¿Cuánto cuesta Travel Rule y está incluido en mi plan de KYC o de verificación?
>
> Travel Rule es un producto independiente que se cobra por uso.
> No está incluido en la verificación de identidad.
> Cuesta \*\*$0.02 por cada intercambio saliente que se inicia** ([precios publicados](#precios), sin niveles por volumen y sin llamadas de ventas).
>         Cuando el enrutamiento necesita una consulta de análisis de blockchain para identificar el VASP de la contraparte, esa consulta se cobra una sola vez a la [tarifa de atribución](#precio-de-la-atribución): desde $0.15 en modalidad gestionada, o \$0.02 con una clave de proveedor existente.
> No se vuelve a cobrar si la monitorización cripto ya analizó la misma wallet.
> Una transferencia por debajo de tu umbral, o una registrada mientras Travel Rule está desactivado, se factura como Transaction Screening; las transferencias entrantes, como los tramos que Didit genera del lado del beneficiario, no se cobran con la tarifa de Travel Rule.

> [accordion] ¿Se me cobrará dos veces cuando Travel Rule y la monitorización cripto se ejecuten a la vez?
>
> No.
> Una transacción `travelRule` se factura en una sola línea: la tarifa de Travel Rule (\$0.02) cuando inicia un intercambio saliente y, en caso contrario, la tarifa estándar de Transaction Screening. La consulta de análisis de blockchain se cobra una sola vez: si la monitorización cripto ya analizó la wallet de destino de la transacción, la [atribución](#atribución-mediante-análisis-de-blockchain) reutiliza ese resultado guardado sin coste adicional.
> Los tramos entrantes que Didit genera del lado del beneficiario nunca se cobran con la tarifa de Travel Rule.

> [accordion] ¿Puede Didit proporcionar documentación o una declaración de capacidades para mi licencia de VASP o mi expediente ante el regulador?
>
> Sí. Las capacidades de KYT y monitorización de transacciones, de análisis AML y de sanciones, de riesgo de wallets mediante análisis de blockchain y de Travel Rule de Didit están documentadas públicamente en docs.didit.me, y puedes citar estas páginas libremente en un expediente regulatorio. Para obtener una declaración formal de capacidades del producto adaptada a una presentación concreta (por ejemplo, una solicitud de licencia AIFC/AFSA, MiCA u otra licencia de VASP), contacta con tu equipo de cuenta de Didit e indica el formato que exige tu regulador.

### Operaciones y datos

> [accordion] ¿Qué ocurre con las transferencias por debajo de mi umbral?
>
> Se resuelven de inmediato como `NOT_APPLICABLE`: no se intenta ningún canal y ningún dato de identidad sale de Didit.
> La transacción se factura como Transaction Screening estándar, no con la tarifa de Travel Rule.
> Didit compara el umbral con el importe convertido a la moneda predeterminada de tu aplicación.
> Si Didit no puede convertir el importe, el umbral no se aplica y se realiza el intercambio.
> El TFR de la UE no tiene mínimo, así que los CASP de la UE deben mantener `threshold_amount` en `0.00`.

> [accordion] ¿Qué pasa si la contraparte nunca responde?
>
> La transferencia permanece en `AWAITING_COUNTERPARTY` hasta que transcurre `confirmation_timeout_hours`. Después, un proceso de barrido la pasa a `EXPIRED` y aplica tu `timeout_outcome` a la transacción subyacente: `HOLD` para revisarla, `REJECT` para rechazarla o `PROCEED` para dejarla intacta. Además, la regla predefinida `tr_eu_expired_review` muestra cada expiración a tus analistas. Una contraparte que nunca llega a recibir el mensaje es un caso distinto: Didit reintenta el envío y, tras el sexto intento fallido, la transferencia pasa a `COUNTERPARTY_VASP_NOT_REACHABLE` (consulta [Entrega y reintentos](#entrega-y-reintentos)).

> [accordion] Mi contraparte no tiene ninguna herramienta de Travel Rule. ¿Puedo cumplir igualmente?
>
> Sí, para eso está el canal `EMAIL`. Su contacto de cumplimiento recibe un enlace de acceso de un solo uso y puede confirmar o rechazar el intercambio desde una página alojada, sin cuenta de Didit, sin clave de API y sin integración. Para los depósitos que ya se liquidaron antes de que fuera posible cualquier intercambio, usa el [registro sunrise posterior al depósito](#registro-sunrise-posterior-al-depósito).

> [accordion] ¿Cómo funcionan los retiros a la wallet propia del usuario?
>
> Declara el destino como sin custodia (`payment_method.method_type: "unhosted_wallet"`). Didit omite el enrutamiento a VASP y, en su lugar, recopila la prueba de que tu cliente controla la wallet (firma de mensaje, prueba Satoshi, captura de pantalla o autodeclaración) mediante el [widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md). Es la obligación del EU TFR sobre wallets sin custodia en forma de API.

> [accordion] ¿Están protegidos los datos personales de la contraparte durante el intercambio?
>
> Sí.
> Hasta que confirmes la propiedad de la wallet por tu parte, los datos personales de la contraparte en una transferencia entrante están enmascarados, tanto en el objeto de la transferencia como en la parte contraparte de la transacción (consulta [Datos de contraparte enmascarados](#datos-de-la-contraparte-enmascarados)).
> Las páginas de recogida por correo electrónico muestran solo el resumen de la transferencia (nombre del VASP ordenante, importe y wallet de destino), nunca los payloads de las personas.
> Los intercambios por canal se realizan sobre HTTPS y, además, los canales de red (`GTR`, `TRUST`, `VERIFYVASP`, `SYGNA`) cifran el payload IVMS con la clave pública del VASP receptor.

> [accordion] Ya hago el seguimiento del cumplimiento de la Travel Rule con mi propio proceso. ¿Puedo limitarme a registrarlo?
>
> Sí. Con Travel Rule desactivada, cualquier `travel_rule_details` que envíes (incluido un `status` aportado por quien llama, actual o heredado) se registra de forma pasiva en la transacción: no se utiliza ningún canal ni se negocia nada. Úsalo para cargar datos históricos o ejecutar tu propio proceso manteniendo un único sistema de registro.

> [accordion] ¿Cómo lo pruebo antes de pasar a producción?
>
> Usa una aplicación de sandbox con Travel Rule activada. Sandbox omite las reglas, la facturación y los webhooks `transaction.created` y `transaction.status.updated`, y todo intercambio **saliente** va al [Didit Test VASP](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md) por el canal `TEST_VASP`, que responde dentro de Didit con el escenario que elijas: aceptar, rechazar, discrepancia de nombre, no accesible, tiempo de espera agotado o sin custodia. Recibes webhooks `travel_rule.status.updated` marcados con `environment: sandbox`, y ningún mensaje llega a una contraparte real.
> Para lo **entrante**, haz que el VASP de prueba te envíe una transferencia con [Trigger Test VASP Inbound Transfer](https://docs.didit.me/es/management-api/travel-rule/trigger-test-vasp-inbound.md) o registra una con `POST /v3/travel-rule/inbound/`; en ambos casos se decide según tu libreta de direcciones de wallets: `ON_HOLD`, `UNCONFIRMED_OWNERSHIP`, `COUNTERPARTY_MISMATCHED_DATA` o `COMPLETED` y después `FINISHED`.
> Para un intercambio entre dos partes con otra aplicación real, usa dos de tus propias aplicaciones **de producción** en el canal `INTERNAL`: la receptora debe ser localizable y demostrar el control de la wallet de destino con un mensaje firmado o un depósito de prueba.

## Próximos pasos

> [card] [Widget de propiedad de wallet](https://docs.didit.me/es/transaction-monitoring/wallet-ownership-widget.md)
>
> Demuestra que un cliente controla una wallet mediante una firma, una prueba de Satoshi, captura de pantalla o autodeclaración.

> [card] [Interoperabilidad](https://docs.didit.me/es/transaction-monitoring/travel-rule-interoperability.md)
>
> Los endpoints orientados a la contraparte que otros VASP usan para comunicarse contigo: TRP, callbacks, recogida por correo electrónico y sunrise.

> [card] [Redes](https://docs.didit.me/es/transaction-monitoring/travel-rule-networks.md)
>
> Qué cubren hoy cada rail y red, y qué sigue requiriendo una membresía.

> [card] [Prueba en sandbox](https://docs.didit.me/es/transaction-monitoring/travel-rule-sandbox.md)
>
> Prueba cada resultado con el Didit Test VASP antes de pasar a producción.

> [card] [Envío de transacciones](https://docs.didit.me/es/transaction-monitoring/transactions.md)
>
> Cómo incluir los datos de Travel Rule en el payload de Create Transaction.

> [card] [Biblioteca de reglas](https://docs.didit.me/es/transaction-monitoring/rules-library.md)
>
> El catálogo completo de reglas predefinidas, incluido el paquete de Travel Rule.

> [card] [Webhooks](https://docs.didit.me/es/integration/webhooks.md)
>
> Suscríbete a travel\_rule.status.updated y a todas las demás familias de eventos.

> [card] [Guía de la consola](https://docs.didit.me/es/transaction-monitoring/console.md)
>
> Consulta el estado de Travel Rule en la vista de detalle de la transacción.


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