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

# Regras de eventos: velocidade, rácio, sequência

> Regras de velocidade, rácio, sequência e correlação sobre dados de eventos na Didit, no mesmo construtor de regras das regras de transação.

[Eventos](https://docs.didit.me/pt/transaction-monitoring/events.md) são avaliados pelo mesmo motor que as transações. Há um único modelo de regras, um único vocabulário de condições e um único conjunto de ações. Uma regra limita-se a declarar a que tipos de registo se aplica.

## Aplica-se a

`scope.record_types` define em que é que uma regra dispara.

| `record_types` | Dispara em |
| - | - |
| omitido ou `["transaction"]` | Apenas transações - **o valor por defeito** |
| `["event"]` | Apenas eventos |
| `["transaction", "event"]` | Ambos |

> [!NOTE]
>
> Deixar o campo de fora mantém a regra apenas para transações. Todas as regras escritas antes de existirem eventos comportam-se exatamente como antes, e uma regra nunca passa a corresponder a inícios de sessão só porque o seu âmbito ficou vazio.

Na consola, isto corresponde ao seletor **Aplica-se a** do passo Trigger da regra. Ao escolher Eventos, surge uma lista de verificação **Categorias de eventos** que restringe ainda mais a regra. Deixe-a toda desmarcada para avaliar todas as categorias.

```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 "o mesmo valor que o evento avaliado". É assim que uma regra diz *por sujeito*, *por dispositivo* ou *por ronda* sem indicar um em concreto.

Os registos sem o valor agrupado nunca são agrupados em conjunto. Um evento sem impressão digital de dispositivo não é "o mesmo dispositivo" que outros eventos sem uma, e um evento que não indica sujeito não é "o mesmo sujeito" que outros eventos anónimos. Quando o evento avaliado não tem valor para um campo `"__current__"`, essa agregação não corresponde, seja qual for o seu operador.

## Campos de eventos

As condições leem caminhos com espaço de nomes. O vocabulário de transações que já conhece (`action_type`, `subject_vendor_data`, `subject_ip_country`, `custom_values.<key>`) também é resolvido num evento.

| Grupo | Caminhos |
| - | - |
| 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 e rede | `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` |
| Jogo | `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` |
| Pagamento e contestação | `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` |
| Segurança e jogo responsável | `event.security.changed_field`, `event.responsible_gambling.identity_match_ref` |
| Telemetria de bots e assistência | `event.bot.timing_variance_ms`, `event.bot.actions_per_minute`, `event.bot.pointer_entropy`, `event.bot.reaction_time_ms_p50`, `event.bot.assistance_indicator` |
| Sinais do sujeito | `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` |
| Outros | `event.payload.<key>`, `custom_values.<key>` |

Os sinais do sujeito são guardados em cache no utilizador monitorizado e não são recalculados por evento. Assim, uma regra pode lê-los à velocidade da ingestão.

## Agregações

### Velocidade

Os redutores que já usa em transações - `count`, `sum`, `avg`, `min`, `max`, `distinct_count` - sobre uma `window` deslizante (`30m`, `24h`, `7d`, `30d`).

### Rácio

Dois redutores sobre a mesma janela. É assim que se expressam as taxas de apostas face a depósitos, de levantamentos face a depósitos, de bónus face a depósitos e de chargebacks.

```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
}
```

Deposite 1000, aposte 20, peça um levantamento, e o rácio é 0,02. É o branqueamento clássico com jogo mínimo.

> [!NOTE]
>
> Um rácio **sem denominador nunca corresponde**. Sem depósitos não é um rácio de zero, é ausência de evidência, e disparar nesse caso assinalaria todos os utilizadores recém-registados.

### Sequência

Predicados ordenados dentro de uma janela. Cada passo corresponde a `action_type`, `event_category` ou a um filtro `match` arbitrário, e pode exigir `min_count` ocorrências antes de a sequência avançar.

```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" }
  ]
}
```

Credential stuffing, depois a tomada de controlo por MFA, depois o redirecionamento do pagamento e, por fim, o esvaziamento da conta. A regra dispara no evento que completa a cadeia, e a evidência correspondente lista os ids de evento de cada passo.

O estado da sequência é mantido por regra e sujeito, pelo que avança à medida que os eventos chegam, em vez de reanalisar a linha temporal. O progresso mais antigo do que a janela é descartado, em vez de ser contado.

### Correlação

Uma junção entre sujeitos: reduz sobre todos os eventos que partilham o grupo deste 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` corresponde às duas extremidades como um conjunto não ordenado. Assim, A→B e B→A caem no mesmo grupo, o que permite que uma regra veja as duas metades de um conluio. Chip dumping, apostas opostas e autorreferenciação de afiliados têm todos esta forma.

Numa regra de correlação, defina sempre `filters` que a restrinjam. Sem eles, a regra considera todos os eventos da janela.

## Regras em tempo real e assíncronas

Algumas regras podem responder dentro do pedido de ingestão e outras não.

| Executa | Que regras |
| - | - |
| **No pedido** | Velocidade, rácio e sequências limitadas (janela até 24 horas) |
| **Em minutos, de forma assíncrona** | Regras de correlação e sequências com uma janela superior a 24 horas |

Um evento cujas regras ainda estão pendentes é devolvido com `"correlation_pending": true`. O estado e a pontuação são atualizados no próprio evento quando o processamento assíncrono termina. Voltar a executar é idempotente, pelo que uma regra nunca aplica a sua pontuação duas vezes.

Esta separação é intencional: uma consulta de anel entre sujeitos não pode fazer um início de sessão esperar.

## Ações

O mesmo vocabulário de ações das regras de transação: `add_score`, `change_status`, `add_tags`, `add_note`, `add_to_list`, `open_case`.

Há duas diferenças nos eventos:

* `change_status` para `AWAITING_USER` é um resultado exclusivo de transações (não existe um fluxo de remediação de eventos) e é aplicado como `IN_REVIEW`.
* `open_case` associa o caso ao **sujeito** e não a uma transação, e regista no caso o identificador do evento correspondente.

## Evidência

Cada correspondência guarda o que foi observado: a janela de agregação, o valor calculado, o valor esperado, os identificadores de eventos amostrados e a **origem de cada campo correspondente**.

| Origem | Significado |
| - | - |
| `server` | A Didit derivou-o (IP, agente do utilizador, origem). Fonte autoritativa. |
| `sdk` | O SDK da Didit reportou-o a partir do dispositivo. |
| `customer` | Os seus sistemas forneceram-no. |

Por isso, um analista consegue distinguir um IP registado pelo servidor de uma indicação fornecida pelo cliente antes de agir sobre uma correspondência. A consola mostra a origem ao lado de cada campo correspondente no painel lateral do evento.

## Exemplos práticos

> [accordion] Branqueamento com jogo mínimo
>
> Depósito, jogo com tokens, levantamento rápido. Condição `event.action_type eq withdrawal_requested`, mais o rácio aposta/depósito indicado acima, com `lte 0.1` em `24h`.

> [accordion] Fraude amigável
>
> Rácio entre `count(chargeback_opened)` e `count(deposit_completed)` por sujeito ao longo de `30d`, `gte 0.5`. Agrupe por `event.payment.payment_fingerprint` em vez de por sujeito para detetar um mesmo instrumento de pagamento em várias contas.

> [accordion] Esvaziamento após tomada de controlo da conta
>
> A sequência `ato_drain` indicada acima, com `add_score 90` e `change_status DECLINED`.

> [accordion] Dumping de fichas
>
> A correlação de pares indicada acima. Aumente `value` para o montante relevante para as suas mesas e adicione `event.gameplay.game_id` a `group_by` para manter os jogos separados.

> [accordion] Jogo com bots e assistência em tempo real
>
> Condições sobre `event.action_type eq bot_signal_observed`, `event.bot.timing_variance_ms lte 10` e `event.device.bot_score gte 90`, com `add_tags`. Combine com um `distinct_count` de `event.device.fingerprint` por IP para identificar um conjunto de dispositivos e não um único script.

> [accordion] Contornar a autoexclusão
>
> Condição sobre `event.action_type eq self_exclusion_match` e `event.payload.re_registration_attempt eq true`, escalando através de `open_case`.

## Próximos passos

> [card] [Ingestão de eventos](https://docs.didit.me/pt/transaction-monitoring/events.md)
>
> O envelope, as dez categorias e o contrato de lote.

> [card] [API de regras](https://docs.didit.me/pt/transaction-monitoring/rules-api.md)
>
> Criar, atualizar e testar regras retrospetivamente de forma programática.


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