> ## 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 ingesta de eventos: monitorización no monetaria

> Envía a Didit actividad no monetaria (logins, juego, bonos, pagos, disputas, seguridad de cuenta) al mismo motor que puntúa tus transacciones.

Las transacciones son el dinero. Los eventos son todo lo demás que sabe tu plataforma: el inicio de sesión que precedió al retiro, la mano que movió fichas entre dos cuentas, el bono que se reclamó dos veces, el contracargo que llegó una semana después.

Los eventos usan una misma estructura para todas las categorías, son idempotentes por diseño y los evalúa el [mismo motor de reglas](https://docs.didit.me/es/transaction-monitoring/event-rules.md) que puntúa tus [transacciones](https://docs.didit.me/es/transaction-monitoring/transactions.md).

> [!NOTE]
>
> La ingesta de eventos es **opcional**. Actívala en **Transactions → Settings → Event monitoring**.
> Hasta que lo hagas, nada cambia: tus reglas de transacciones existentes siguen disparándose solo sobre transacciones, y no es posible crear una regla de eventos por accidente, porque una regla se aplica a las transacciones salvo que incluyas eventos de forma explícita.
>
> Mientras no esté activada, todos los canales de escritura (`POST /v3/events/`, `POST /v3/events/batch/`, `POST /v3/events/sdk-token/` y el canal de dispositivo `/v1/events/`) responden `403` con `{"code": "event_monitoring_disabled"}`, y no se almacena, enriquece ni evalúa nada. Las lecturas no se ven afectadas.

## Endpoints

| Endpoint | Autenticación | Para qué sirve |
| - | - | - |
| `POST /v3/events/` | Clave de API | Un evento desde tu backend |
| `POST /v3/events/batch/` | Clave de API | Hasta 500 eventos en una sola solicitud |
| `POST /v3/events/sdk-token/` | Clave de API | Emitir una credencial de dispositivo con alcance limitado |
| `POST /v1/events/` | `X-Monitoring-Token` | Un evento desde el SDK del dispositivo |
| `POST /v1/events/batch/` | `X-Monitoring-Token` | Un búfer del SDK vaciado |
| `GET /v3/events/` | Clave de API | Listar y filtrar eventos |
| `GET /v3/events/{event_uuid}/` | Clave de API | Un evento con la evidencia de sus reglas |
| `GET /v3/events/subjects/{vendor_data}/` | Clave de API | La línea de tiempo de un sujeto (consulta `entity_type` más abajo) |
| `GET /v3/events/enrichment-metrics/` | Clave de API | Estado de la caché de enriquecimiento de IP |

La ruta `/v3/` es la ruta del servidor y usa la misma autenticación `x-api-key` que el resto de la API de transacciones. La ruta `/v1/events/` es la ruta del dispositivo: consulta [Envío de eventos desde el SDK](https://docs.didit.me/es/transaction-monitoring/sdk-event-submission.md).

## El sobre

```bash theme={null}
curl -X POST https://verification.didit.me/v3/events/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "login-2026-08-31-000001",
    "event_category": "auth",
    "action_type": "login",
    "occurred_at": "2026-08-31T20:40:31.123Z",
    "time_zone": "UTC",
    "subject": {
      "entity_type": "individual",
      "vendor_data": "user_391"
    },
    "session": { "session_id": "web-session-abc", "sequence": 142 },
    "device_context": {
      "fingerprint": "didit-fp-v2:a8c1",
      "network_context": { "ip_address": "203.0.113.42" }
    },
    "payload": { "method": "password" }
  }'
```

```json theme={null}
{
  "event_uuid": "0f2b...",
  "event_id": "login-2026-08-31-000001",
  "status": "ACCEPTED",
  "score": 0,
  "rules_evaluated_count": 6,
  "rules_matched_count": 0,
  "correlation_pending": false,
  "retention_class": "standard",
  "expires_at": "2026-09-30T20:40:31.123Z",
  "idempotent_replay": false,
  "rule_matches": []
}
```

| Campo | Obligatorio | Notas |
| - | - | - |
| `event_id` | sí | Tu propio identificador, único por aplicación. Es la clave de idempotencia. |
| `event_category` | sí | Una de las diez categorías que se indican más abajo. |
| `action_type` | sí | Cadena libre, de hasta 128 caracteres. |
| `occurred_at` | sí | Cuándo ocurrió en tu sistema. Hasta 7 días en el pasado y 5 minutos en el futuro. |
| `subject.vendor_data` | sí | El ID de tu usuario. Se resuelve al mismo usuario al que se resolvería una transacción. |
| `subject.entity_type` | no | `individual` (predeterminado) o `company`. |
| `business.vendor_data` | no | La empresa a la que pertenece el evento. |
| `session` | no | `session_id`, `sequence`, `page_url`, `referrer`. |
| `device_context` | no | `fingerprint`, `persistent_device_id`, `bot_score` y `network_context.ip_address`. |
| `transaction_context` | no | `amount`, `currency`, `direction`, `payment_reference_id`. |
| `payload` | no | Los campos de dominio de la categoría. Hasta 16 KB. |
| `custom_values` | no | Hasta 100 claves escalares, accesibles desde las reglas como `custom_values.<key>`. |

## Categorías

Diez categorías de primer nivel, cada una con validación tipada y [campos de regla](https://docs.didit.me/es/transaction-monitoring/event-rules.md#campos-de-evento) gestionados.

| Categoría | Acciones habituales |
| - | - |
| `auth` | `signup`, `login`, `login_failed`, `logout`, `password_forgot`, `password_reset`, `mfa_reset`, `mfa_challenge` |
| `session` | `session_started`, `session_ended`, `page_view`, `sdk_loaded`, `device_seen`, `bot_signal_observed`, `sdk_heartbeat` |
| `gameplay` | `round_started`, `round_completed`, `bet_placed`, `bet_settled`, `cashout`, `limit_change`, `p2p_settlement` |
| `bonus` | `bonus_claimed`, `bonus_wagered`, `bonus_released`, `promotion_viewed` |
| `affiliate` | `affiliate_attributed`, `referral_clicked`, `campaign_joined`, `commission_event` |
| `payment` | `deposit_initiated`, `deposit_completed`, `withdrawal_requested`, `withdrawal_completed`, `withdrawal_address_changed`, `payment_instrument_seen` |
| `dispute` | `chargeback_opened`, `chargeback_won`, `chargeback_lost`, `refund_issued`, `payment_dispute_updated` |
| `security` | `login_attempt`, `login_succeeded`, `login_failed`, `password_changed`, `mfa_changed`, `credential_reset`, `country_changed`, `device_changed`, `account_locked` |
| `responsible_gambling` | `self_exclusion_checked`, `self_exclusion_match`, `re_registration_attempt`, `limit_breach_attempt`, `registry_status_changed` |
| `custom` | Cualquier acción que definas |

`auth` es la categoría amplia de producto; `security` es el subconjunto orientado al riesgo, con el ciclo de vida ordenado que utilizan las reglas de toma de control de cuentas.

### Claves obligatorias del payload

Algunas acciones no se pueden correlacionar sin claves concretas, así que la validación las rechaza en lugar de almacenar evidencias que nadie puede vincular.

| Acción | Obligatorias |
| - | - |
| `gameplay.p2p_settlement` | `game_id`, `counterparty_vendor_data`, `stake_amount`, `net_result_amount`, `role` y una de `hand_id` / `round_id` / `match_id` |
| `gameplay.bet_placed`, `gameplay.bet_settled` | `game_id` |
| `payment.deposit_*`, `payment.withdrawal_completed`, `payment.withdrawal_requested`, `payment.deposit_initiated` | `payment_reference_id`, `amount`, `currency`, `payment_method`, `status` |
| `payment.withdrawal_address_changed` | `withdrawal_address_hash` |
| `dispute.chargeback_*` | `payment_reference_id` y una de `dispute_id` / `chargeback_id` |
| `security.*_changed` | `changed_field`; los cambios en el control de la cuenta o de los pagos también requieren `previous_reference_hash` o `new_reference_hash` |
| `session.bot_signal_observed` | `telemetry_schema_version`, además de un `bot_score` o al menos una métrica de telemetría |
| `responsible_gambling.self_exclusion_match` | `registry_source`, `exclusion_status`, `identity_match_ref` |

> [!WARNING]
>
> Envía **referencias y hashes**, nunca secretos en claro. Los instrumentos de pago, los destinos de retirada y los cambios en el control de la cuenta se almacenan como la referencia con hash que envías. Nunca envíes un número de tarjeta, una dirección de retirada completa, un hash de contraseña ni un secreto de MFA.

### Ejemplo: una liquidación P2P

```json theme={null}
{
  "event_id": "p2p-hand-8842-user-391",
  "event_category": "gameplay",
  "action_type": "p2p_settlement",
  "occurred_at": "2026-08-31T12:34:17.392Z",
  "subject": { "vendor_data": "user_391" },
  "payload": {
    "game_id": "poker_holdem",
    "table_id": "table_17",
    "hand_id": "hand_8842",
    "role": "winner",
    "counterparty_vendor_data": "user_812",
    "stake_amount": "250.00",
    "net_result_amount": "240.50",
    "effective_margin": "0.038",
    "operator_ledger_ref": "ledger_998123"
  }
}
```

### Ejemplo: un contracargo

```json theme={null}
{
  "event_id": "chargeback-cb_921-opened",
  "event_category": "dispute",
  "action_type": "chargeback_opened",
  "occurred_at": "2026-08-31T09:22:05.000Z",
  "subject": { "vendor_data": "user_391" },
  "transaction_context": {
    "amount": "1000.00",
    "currency": "EUR",
    "payment_reference_id": "dep_735"
  },
  "payload": {
    "dispute_id": "disp_498",
    "chargeback_id": "cb_921",
    "reason_code": "fraudulent",
    "liability_shift": false
  }
}
```

Los ciclos de vida de las disputas solo permiten añadir eventos: una corrección es un nuevo evento `dispute`, nunca una edición del primero.

## Idempotencia

`event_id` es único por aplicación y constituye todo el contrato de idempotencia.

* **Mismo `event_id`, mismo contenido** devuelve `200` con `"idempotent_replay": true` y el evento almacenado originalmente. Reintenta tantas veces como quieras.
* **Mismo `event_id`, contenido distinto** devuelve `409`. Has reutilizado un ID por error.

## Lotes

`POST /v3/events/batch/` acepta hasta **500 eventos**. Un lote puede tener éxito parcial por diseño: una vista de página mal formada nunca debe afectar al contracargo adyacente.

```json theme={null}
{
  "accepted_count": 2,
  "replayed_count": 0,
  "rejected_count": 1,
  "results": [
    { "index": 0, "outcome": "rejected", "errors": { "occurred_at": ["This field is required."] } },
    { "index": 1, "outcome": "accepted", "event_uuid": "…", "status": "ACCEPTED" },
    { "index": 2, "outcome": "accepted", "event_uuid": "…", "status": "IN_REVIEW" }
  ]
}
```

La respuesta es `207 Multi-Status` cuando se rechazó algo y `201 Created` cuando todo se procesó correctamente.

## Estados

| Estado | Significado |
| - | - |
| `ACCEPTED` | Almacenado. Ninguna regla cambió su estado (es la respuesta normal para la mayoría de los eventos). |
| `APPROVED` | Se ejecutó una regla y la puntuación se mantuvo por debajo de tu umbral de revisión. |
| `IN_REVIEW` | Una regla lo llevó por encima del umbral de revisión o fijó el estado directamente. |
| `DECLINED` | Una regla lo rechazó. |

`correlation_pending: true` significa que todavía tiene que ejecutarse una regla que abarca varios sujetos; se resuelve en cuestión de minutos y el estado y la puntuación del evento se actualizan directamente en el evento. Consulta las [reglas asíncronas](https://docs.didit.me/es/transaction-monitoring/event-rules.md#reglas-en-tiempo-real-y-asíncronas).

## Retención

Los eventos tienen un volumen muy superior al de las transacciones, así que cada uno se asigna a una clase de retención al llegar.

| Clase | Retención en caliente predeterminada | Qué se incluye aquí |
| - | - | - |
| `low_value` | 14 días | Vistas de página, heartbeats, pings de dispositivo detectado, telemetría de bots, vistas de promociones |
| `standard` | 30 días | Auth, sesión, juego, bonos, afiliados, personalizados |
| `risk_relevant` | 90 días | Eventos de seguridad y de juego responsable, y **cualquier evento que haya coincidido con una regla** |
| `monetary_or_compliance` | Retención de transacciones | Eventos de pago y de disputa |

De la tabla se derivan dos reglas:

* Un evento que coincide con una regla es una evidencia, por lo que se promueve automáticamente a `risk_relevant`.
* Los eventos de pago y de disputa conservan la retención de transacciones. Nunca expiran según el calendario de eventos, y las anulaciones por clase no pueden acortarla.

Configura períodos de retención distintos para las tres clases que expiran en cada aplicación en **Transactions → Settings → Event monitoring** (de 1 a 730 días cada una).

## Enriquecimiento de IP

Los eventos llevan el mismo [enriquecimiento de IP](https://docs.didit.me/es/transaction-monitoring/ip-enrichment.md) que las transacciones (país, ASN e indicadores de VPN/proxy y de centro de datos), y se consulta el enriquecimiento **por dirección IP única, nunca por evento**. Una sesión que genera 200 vistas de página desde una misma dirección consulta el enriquecimiento de esa dirección una sola vez.

La telemetría de bajo valor va más allá: solo lee el enriquecimiento si otro evento ya consultó el enriquecimiento de esa dirección. Nunca dispara una consulta por su cuenta.

`GET /v3/events/enrichment-metrics/` informa del resultado, y la consola muestra las mismas cifras encima de la lista de eventos:

```json theme={null}
{
  "events_ingested": 128450,
  "enrichment_lookups": 41230,
  "enrichment_cache_hits": 40118,
  "enrichment_provider_calls": 1112,
  "enrichment_skipped_low_value": 74320,
  "unique_ips_seen": 1112,
  "cache_hit_rate": 0.973,
  "unique_ip_ratio": 0.0087,
  "provider_calls_per_1k_events": 8.65,
  "period_days": 30
}
```

## Lectura de eventos

```bash theme={null}
curl "https://verification.didit.me/v3/events/?event_category=payment&event_category=dispute&matched_only=true" \
  -H "x-api-key: YOUR_API_KEY"
```

Filtros: `event_category`, `action_type`, `status`, `retention_class`, `subject_vendor_data`, `business_vendor_data`, `session_id`, `device_fingerprint`, `ip_address`, `game_id`, `round_id`, `affiliate_code`, `payment_reference_id`, `counterparty_vendor_data`, `matched_only`, `occurred_from`, `occurred_to`, `search`. Los filtros con varios valores repiten el parámetro (`?status=A&status=B`).

### Cronología de un sujeto

```bash theme={null}
curl "https://verification.didit.me/v3/events/subjects/acct_9931/?entity_type=company" \
  -H "x-api-key: YOUR_API_KEY"
```

Un `vendor_data` solo es único **dentro de** un tipo de entidad: el mismo ID puede designar a un usuario y a una empresa, y Didit los trata como dos sujetos distintos. `entity_type` indica cuál de los dos solicitas: `individual` (el valor predeterminado) o `company`. Si lo omites con el ID de una empresa, obtienes la cronología de la persona física, no ambas cronologías. Se aplican los mismos filtros de la lista.

`GET /v3/events/{event_uuid}/` añade el payload, el contexto del dispositivo, el enriquecimiento de IP, las señales de riesgo del sujeto almacenadas en caché y cada coincidencia de regla con su evidencia, incluido si cada campo coincidente fue derivado por el servidor o el SDK, o proporcionado por el cliente.

`DELETE /v3/events/{event_uuid}/delete/` elimina un evento. Ninguna lectura vuelve a devolverlo, y la eliminación es irreversible.

## Siguientes pasos

> [card] [Reglas sobre eventos](https://docs.didit.me/es/transaction-monitoring/event-rules.md)
>
> Reglas de velocidad, proporción, secuencia y correlación sobre los datos de eventos.

> [card] [Envío de eventos desde el SDK](https://docs.didit.me/es/transaction-monitoring/sdk-event-submission.md)
>
> Captura eventos directamente desde el dispositivo con una credencial de alcance limitado.


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