> ## 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.

# Reglas de eventos: velocidad/ratio/secuencia/correlación

> Reglas de velocidad, ratio, secuencia y correlación entre sujetos sobre eventos en Didit, con el mismo editor que tus reglas de transacciones.

Los [eventos](https://docs.didit.me/es/transaction-monitoring/events.md) los evalúa el mismo motor que las transacciones. Hay un único modelo de reglas, un único vocabulario de condiciones y un único conjunto de acciones: una regla simplemente declara a qué tipos de registro se aplica.

## Se aplica a

`scope.record_types` determina para qué se activa una regla.

| `record_types` | Se activa para |
| - | - |
| omitido o `["transaction"]` | Solo transacciones: **el valor predeterminado** |
| `["event"]` | Solo eventos |
| `["transaction", "event"]` | Ambos |

> [!NOTE]
>
> Si lo omites, la regla se aplica solo a transacciones. Toda regla escrita antes de que existieran los eventos se comporta exactamente igual que antes, y una regla nunca empieza a coincidir con inicios de sesión porque su alcance estuviera vacío.

En la consola, esto es el selector **Se aplica a** del paso de disparador de una regla. Al elegir Eventos aparece una lista de casillas **Categorías de eventos** que acota aún más la regla; deja todas sin marcar para evaluar todas las categorías.

```json theme={null}
{
  "title": "Failed login burst",
  "scope": {
    "record_types": ["event"],
    "event_categories": ["security"]
  },
  "aggregation": [
    {
      "metric": "count",
      "operator": "gte",
      "value": 3,
      "window": "30m",
      "filters": {
        "subject_vendor_data": "__current__",
        "event.action_type": "login_failed"
      }
    }
  ],
  "actions": [
    { "type": "add_score", "value": 40 },
    { "type": "change_status", "value": "IN_REVIEW" }
  ]
}
```

`"__current__"` significa "el mismo valor que el del evento que se está evaluando": así es como una regla expresa *por sujeto*, *por dispositivo* o *por ronda* sin nombrar ninguno.

## Campos de evento

Las condiciones leen rutas con espacio de nombres. El vocabulario de transacciones que ya conoces (`action_type`, `subject_vendor_data`, `subject_ip_country`, `custom_values.<key>`) también se resuelve en un evento.

| Grupo | Rutas |
| - | - |
| Evento | `event.category`, `event.action_type`, `event.occurred_at`, `event.amount`, `event.currency`, `event.direction`, `event.session_id`, `event.session_sequence`, `event.score`, `event.status`, `event.ingest_source`, `event.retention_class`, `event.subject_vendor_data`, `event.business_vendor_data` |
| Dispositivo y red | `event.device.fingerprint`, `event.device.persistent_device_id`, `event.device.bot_score`, `event.ip.address`, `event.ip.country`, `event.ip.asn_number`, `event.ip.asn_organization`, `event.ip.is_vpn_or_tor`, `event.ip.is_data_center`, `event.ip.proxy_type`, `event.ip.country_name`, `event.ip.city`, `event.ip.connection_type`, `event.ip.travel_distance_km`, `event.ip.travel_speed_kmh` |
| Juego | `event.gameplay.game_id`, `event.gameplay.table_id`, `event.gameplay.round_id`, `event.gameplay.hand_id`, `event.gameplay.match_id`, `event.gameplay.market_id`, `event.gameplay.side`, `event.gameplay.role`, `event.gameplay.counterparty_vendor_data`, `event.gameplay.net_result_amount`, `event.bonus.bonus_id`, `event.affiliate.affiliate_code` |
| Pago y disputa | `event.payment.reference_id`, `event.payment.payment_fingerprint`, `event.payment.instrument_reference_hash`, `event.payment.withdrawal_address_hash`, `event.dispute.dispute_id`, `event.dispute.chargeback_id` |
| Seguridad y juego responsable | `event.security.changed_field`, `event.responsible_gambling.identity_match_ref` |
| Telemetría de bots y asistencia | `event.bot.timing_variance_ms`, `event.bot.actions_per_minute`, `event.bot.pointer_entropy`, `event.bot.reaction_time_ms_p50`, `event.bot.assistance_indicator` |
| Señales del sujeto | `subject.email.risk_score`, `subject.email.social_count`, `subject.email.is_disposable`, `subject.email.deliverability`, `subject.email.domain_reputation`, `subject.email.first_seen_days`, `subject.email.is_breached`, `subject.phone.risk_score`, `subject.phone.line_type`, `subject.phone.social_count`, `subject.phone.carrier`, `subject.phone.country`, `subject.phone.is_disposable` |
| Cualquier otra | `event.payload.<key>`, `custom_values.<key>` |

Las señales del sujeto se almacenan en caché en el usuario monitorizado y no se recalculan en cada evento, de modo que una regla puede leerlas a velocidad de ingesta.

## Agregaciones

### Velocidad

Los reductores que ya usas en las transacciones (`count`, `sum`, `avg`, `min`, `max`, `distinct_count`) sobre una ventana móvil `window` (`30m`, `24h`, `7d`, `30d`).

### Ratio

Dos reductores sobre la misma ventana. Así se expresan las ratios de apuesta frente a depósito, retirada frente a depósito, bono frente a depósito y las tasas de contracargos.

```json theme={null}
{
  "metric": "ratio",
  "window": "24h",
  "filters": { "subject_vendor_data": "__current__" },
  "numerator":   { "metric": "sum", "field": "event.amount", "filters": { "event.action_type": "bet_placed" } },
  "denominator": { "metric": "sum", "field": "event.amount", "filters": { "event.action_type": "deposit_completed" } },
  "operator": "lte",
  "value": 0.1
}
```

Deposita 1,000, apuesta 20, solicita una retirada, y la ratio es 0.02: el clásico blanqueo mediante juego mínimo.

> [!NOTE]
>
> Una ratio **sin denominador nunca coincide**. No tener depósitos no es una ratio de cero, es ausencia de evidencia, y que la regla se active en ese caso marcaría a todos los usuarios recién creados.

### Secuencia

Predicados ordenados dentro de una ventana. Cada paso se ajusta a `action_type`, `event_category` o a un filtro `match` arbitrario, y puede exigir `min_count` ocurrencias antes de que la secuencia avance.

```json theme={null}
{
  "metric": "sequence",
  "key": "ato_drain",
  "window": "24h",
  "steps": [
    { "event_category": "security", "action_type": "login_failed", "min_count": 3 },
    { "event_category": "security", "action_type": "mfa_changed" },
    { "event_category": "payment",  "action_type": "withdrawal_address_changed" },
    { "event_category": "payment",  "action_type": "withdrawal_requested" }
  ]
}
```

Relleno de credenciales (credential stuffing), luego la toma de control del MFA, luego la redirección del pago y luego el vaciado de la cuenta. La regla se dispara con el evento que completa la cadena, y la evidencia coincidente enumera los ids de evento de cada paso.

El estado de la secuencia se guarda por regla y sujeto, de modo que avanza a medida que llegan los eventos en lugar de volver a recorrer la línea de tiempo. El progreso anterior a la ventana se descarta en lugar de contabilizarse.

### Correlación

Una unión entre sujetos: aplica un reductor a todos los eventos que comparten el grupo de este evento.

```json theme={null}
{
  "metric": "correlation",
  "window": "7d",
  "pair": true,
  "group_by": ["subject_vendor_data", "event.gameplay.counterparty_vendor_data"],
  "filters": { "event.action_type": "p2p_settlement" },
  "correlate": {
    "metric": "sum",
    "field": "event.gameplay.net_result_amount",
    "filters": { "event.gameplay.role": "winner" }
  },
  "operator": "gte",
  "value": 500
}
```

`"pair": true` trata los dos extremos como un conjunto no ordenado, de modo que A→B y B→A caen en el mismo grupo, y eso es lo que permite que una sola regla vea las dos mitades de una colusión. El chip dumping, las apuestas opuestas y la autorreferencia de afiliados tienen todos esta forma.

Añade siempre `filters` que delimiten una regla de correlación. Sin ellos, considera todos los eventos de la ventana.

## Reglas en tiempo real y asíncronas

Algunas reglas pueden responder dentro de la solicitud de ingesta y otras no.

| Se ejecuta | Qué reglas |
| - | - |
| **En la solicitud** | Velocidad, ratio y secuencias acotadas (ventana de hasta 24 horas) |
| **En pocos minutos, de forma asíncrona** | Reglas de correlación y secuencias con una ventana de más de 24 horas |

Un evento cuyas reglas siguen pendientes se devuelve con `"correlation_pending": true`. Su estado y su puntuación se actualizan en el propio evento cuando termina la pasada asíncrona; volver a ejecutarla es idempotente, así que una regla nunca aplica su puntuación dos veces.

Esta separación es intencionada: una consulta de red entre sujetos no debe hacer esperar a un inicio de sesión.

## Acciones

El mismo vocabulario de acciones que las reglas de transacciones: `add_score`, `change_status`, `add_tags`, `add_note`, `add_to_list`, `open_case`.

Dos diferencias en los eventos:

* `change_status` a `AWAITING_USER` es un resultado exclusivo de las transacciones (no existe un flujo de subsanación para eventos) y se aplica como `IN_REVIEW`.
* `open_case` vincula el caso al **sujeto** en lugar de a una transacción, y registra en el caso el ID del evento coincidente.

## Evidencia

Cada coincidencia almacena lo que observó: la ventana de agregación, el valor calculado, el valor esperado, ID de eventos muestreados y el **origen de cada campo coincidente**.

| Origen | Significado |
| - | - |
| `server` | Lo derivó Didit (IP, user agent, origen). Es la fuente de referencia. |
| `sdk` | Lo reportó el SDK de Didit desde el dispositivo. |
| `customer` | Lo proporcionaron tus sistemas. |

Así, un analista puede distinguir una IP registrada por el servidor de un indicio proporcionado por el cliente antes de tomar medidas respecto de una coincidencia. La consola muestra el origen junto a cada campo coincidente en el panel lateral del evento.

## Ejemplos prácticos

> [accordion] Blanqueo con juego mínimo
>
> Depósito, juego simbólico, retiro rápido. Condición `event.action_type eq withdrawal_requested`, más la proporción entre apuestas y depósitos indicada anteriormente, con `lte 0.1` durante `24h`.

> [accordion] Fraude amistoso
>
> Proporción de `count(chargeback_opened)` respecto a `count(deposit_completed)` por sujeto durante `30d`, `gte 0.5`. Agrupa por `event.payment.payment_fingerprint` en lugar de por sujeto para detectar un mismo instrumento en varias cuentas.

> [accordion] Vaciado por toma de control de cuenta
>
> La secuencia `ato_drain` indicada arriba, con `add_score 90` y `change_status DECLINED`.

> [accordion] Chip dumping
>
> La correlación de pares indicada arriba. Eleva `value` al importe que sea relevante para tus mesas y añade `event.gameplay.game_id` a `group_by` para mantener las partidas separadas.

> [accordion] Juego con bots y asistencia en tiempo real
>
> Condiciones: `event.action_type eq bot_signal_observed`, `event.bot.timing_variance_ms lte 10` y `event.device.bot_score gte 90`, con `add_tags`. Combínalas con un `distinct_count` de `event.device.fingerprint` por IP para encontrar una granja en lugar de un único script.

> [accordion] Evasión de la autoexclusión
>
> Condición: `event.action_type eq self_exclusion_match` y `event.payload.re_registration_attempt eq true`, con escalado mediante `open_case`.

## Siguientes pasos

> [card] [Ingesta de eventos](https://docs.didit.me/es/transaction-monitoring/events.md)
>
> La envoltura, las diez categorías y el contrato de lotes.

> [card] [API de reglas](https://docs.didit.me/es/transaction-monitoring/rules-api.md)
>
> Crea, actualiza y prueba reglas con datos históricos de forma programática.


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