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

# Revisar uma transação negada

> Leia uma decisão DENY ou REVIEW do Tracer para encontrar a regra ou o limite por trás dela, recupere o registro armazenado mais tarde e verifique seu evento de auditoria durante uma auditoria.

export const GAuditTrail = ({children}) => <Tooltip headline="Audit trail" tip="A chronological, immutable record of every action and transaction in the system — essential for regulatory compliance and dispute resolution." cta="See glossary" href="/en/glossary">
    {children}
  </Tooltip>;

Uma validação voltou `DENY` ou `REVIEW` e alguém está perguntando por quê. Este guia leva você da decisão que o Tracer devolveu até uma regra com nome ou um limite de gasto com nome. De lá ele chega ao registro armazenado e ao <GAuditTrail>rastro de auditoria</GAuditTrail> que você pode entregar a um auditor meses depois.

**O que muda na sua operação:** a resposta para "por que isso foi bloqueado?" deixa de ser uma busca em logs. Cada decisão chega com os identificadores do que a produziu. O mesmo registro responde por id anos depois, e o evento de auditoria dele pode ser conferido contra a cadeia de hashes.

<Tip>
  **Para quem é este guia?** Desenvolvedores que integram a chamada de validação, times de suporte e disputas que respondem perguntas de clientes, e responsáveis por compliance que preparam evidências. Os passos 1 a 4 precisam apenas da resposta que você já tem; os passos 5 a 8 usam os endpoints de consulta.
</Tip>

## Antes de começar

***

* [ ] Tracer em execução e acessível, com uma API key — veja [Primeiros passos](./getting-started.mdx)
* [ ] Uma resposta `DENY` ou `REVIEW` para trabalhar, ou o `validationId` de uma
* [ ] Familiaridade com o que regras e limites fazem — veja o [Motor de regras](./rule-engine.mdx) e os [Limites de gasto](./spending-limits.mdx)

Todas as chamadas abaixo enviam a API key como `X-API-Key`.

***

## Passo 1: Leia a decisão que o Tracer devolveu

***

`POST /v1/validations` responde com a decisão completa. Uma requisição nova responde `201`; repetir um `requestId` responde `200` com a decisão que o Tracer já registrou para aquela chave.

```bash theme={null}
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)

curl -X POST http://localhost:4020/v1/validations \
  -H "X-API-Key: your-secure-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "requestId": "7c3f1b8e-5a2d-4c6b-9e1f-0a4d8b2c6e30",
    "transactionType": "CARD",
    "subType": "purchase",
    "amount": "1500.00",
    "currency": "BRL",
    "transactionTimestamp": "'"$TS"'",
    "account": {
      "accountId": "550e8400-e29b-41d4-a716-446655440100",
      "type": "checking",
      "status": "active"
    },
    "merchant": {
      "merchantId": "550e8400-e29b-41d4-a716-446655440103",
      "category": "5411",
      "country": "BR",
      "name": "Acme Store"
    },
    "metadata": {
      "channel": "mobile"
    }
  }'
```

Uma negativa produzida por uma regra fica assim:

```json theme={null}
{
  "validationId": "8f14e45f-ea3b-4c6e-9a1c-2b7d5e0a91c4",
  "requestId": "7c3f1b8e-5a2d-4c6b-9e1f-0a4d8b2c6e30",
  "decision": "DENY",
  "matchedRuleIds": [
    "3c8a5b21-9f4d-4e17-8b6a-1d2e3f405162"
  ],
  "evaluatedRuleIds": [
    "3c8a5b21-9f4d-4e17-8b6a-1d2e3f405162",
    "a6b7c8d9-0e1f-4a2b-9c3d-4e5f60718293"
  ],
  "reason": "Rule matched with DENY action",
  "totalRulesLoaded": 2,
  "truncated": false,
  "limitUsageDetails": [],
  "processingTimeMs": 9.4,
  "evaluatedAt": "2026-07-31T14:05:09.481Z"
}
```

| Campo                              | O que ele diz                                                                                           |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `validationId`                     | A chave desta decisão. Tudo o que vem adiante neste guia parte dela                                     |
| `decision`                         | `ALLOW`, `DENY` ou `REVIEW`                                                                             |
| `reason`                           | O que produziu a decisão — veja o [Passo 2](#passo-2-distinga-uma-negativa-por-regra-de-uma-por-limite) |
| `matchedRuleIds`                   | Toda regra que casou com esta transação, qualquer que seja a ação que ela carrega                       |
| `evaluatedRuleIds`                 | As regras que o Tracer avaliou para esta transação                                                      |
| `limitUsageDetails`                | Uma entrada por limite de gasto que o Tracer verificou                                                  |
| `totalRulesLoaded` / `truncated`   | Quantas regras foram carregadas e se `MAX_RULES_PER_REQUEST` cortou o conjunto                          |
| `processingTimeMs` / `evaluatedAt` | Quanto tempo a avaliação levou e quando ela rodou                                                       |

Para o schema completo de requisição e resposta, veja [Validar uma transação](/pt/reference/tracer/validate-transaction).

<Note>
  Guarde o `validationId` junto ao seu próprio registro da transação. É a chave que o [Passo 5](#passo-5-recupere-o-registro-mais-tarde) recebe e também o `resourceId` do evento de auditoria no [Passo 7](#passo-7-puxe-o-evento-de-auditoria-por-trás-da-decisão).
</Note>

***

## Passo 2: Distinga uma negativa por regra de uma por limite

***

Leia `reason` primeiro. Ele nomeia o que produziu a decisão e diz qual dos dois passos seguintes tomar.

| `reason`                        | O que aconteceu                                                              | Vá para                                                                                           |
| ------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `Rule matched with DENY action` | Casou uma regra cuja ação é `DENY`                                           | [Passo 3](#passo-3-nomeie-a-regra)                                                                |
| `limit_exceeded`                | O valor empurraria um limite de gasto além do seu teto                       | [Passo 4](#passo-4-nomeie-o-limite-de-gasto)                                                      |
| `No matching rules found`       | Nenhuma regra casou, então o Tracer aplicou `DEFAULT_DECISION_WHEN_NO_MATCH` | Revise essa configuração na página de [variáveis de ambiente](./tracer-environment-variables.mdx) |

`reason` carrega o mesmo texto em decisões `REVIEW` — `Rule matched with REVIEW action` — e o Passo 3 lê uma revisão do mesmo jeito que lê uma negativa.

<Note>
  Em uma negativa por regra, `limitUsageDetails` volta vazio porque o Tracer para antes da verificação de limites — não porque nenhum limite se aplique à conta.
</Note>

***

## Passo 3: Nomeie a regra

***

`matchedRuleIds` lista toda regra que casou, qualquer que seja a ação que cada uma carrega — uma regra `DENY` e uma regra `ALLOW` podem aparecer na mesma negativa. Recupere cada uma e leia sua `action` para encontrar a regra por trás da decisão:

```http theme={null}
GET /v1/rules/3c8a5b21-9f4d-4e17-8b6a-1d2e3f405162
X-API-Key: {api_key}
```

A regra carrega o `name`, a `description`, a `expression`, a `action` e os `scopes` que um colega precisa para ver por que ela disparou — veja [Recuperar uma regra](/pt/reference/tracer/retrieve-rule).

Compare `matchedRuleIds` com `evaluatedRuleIds` quando a pergunta for a oposta — "por que minha regra *não* disparou?". Uma regra ausente de `evaluatedRuleIds` não foi avaliada para esta transação, então comece pelo status e pelo escopo dela antes da expressão.

<Tip>
  Uma regra deletada depois da decisão não responde mais em `GET /v1/rules/{id}`. A história dela, incluindo quem a deletou, fica no rastro de auditoria — veja [Auditoria e compliance](./audit-compliance.mdx).
</Tip>

***

## Passo 4: Nomeie o limite de gasto

***

Em uma negativa `limit_exceeded`, `limitUsageDetails` traz uma entrada por limite que o Tracer verificou, e as entradas marcadas com `"exceeded": true` são as que o valor empurraria além do teto:

```json theme={null}
{
  "validationId": "8f14e45f-ea3b-4c6e-9a1c-2b7d5e0a91c4",
  "requestId": "7c3f1b8e-5a2d-4c6b-9e1f-0a4d8b2c6e30",
  "decision": "DENY",
  "matchedRuleIds": [],
  "evaluatedRuleIds": [
    "a6b7c8d9-0e1f-4a2b-9c3d-4e5f60718293"
  ],
  "reason": "limit_exceeded",
  "totalRulesLoaded": 2,
  "truncated": false,
  "limitUsageDetails": [
    {
      "limitId": "b2d4f6a8-1c3e-4507-9b8d-6f0a2c4e6810",
      "limitAmount": "50000",
      "scope": "(segment:2f1c9b7e-40a5-4d18-9c6b-3e7f5a0d1b24,transactionType:CARD)",
      "period": "DAILY",
      "currentUsage": "51500",
      "attemptedAmount": "1500",
      "exceeded": true
    },
    {
      "limitId": "d4f6a8b2-3e5c-4709-8b6d-0a2c4e681012",
      "limitAmount": "400000",
      "scope": "(account:550e8400-e29b-41d4-a716-446655440100)",
      "period": "MONTHLY",
      "currentUsage": "128400",
      "attemptedAmount": "1500",
      "exceeded": false
    }
  ],
  "processingTimeMs": 14.2,
  "evaluatedAt": "2026-07-31T14:05:09.481Z"
}
```

Leia a entrada excedida como a aritmética da negativa: `attemptedAmount` contra `limitAmount`, com `currentUsage` informando o que o período atual daquele limite e o escopo que casou teriam se esta transação fosse permitida. Na entrada acima, uma compra de `1500` levaria um teto diário de `50000` a `51500`.

Um limite `PER_TRANSACTION` não mantém contagem, então sua entrada informa `currentUsage` como `0` e `attemptedAmount` contra `limitAmount` é toda a comparação.

`GET /v1/limits/{limitId}` dá o nome e a configuração atuais do limite — veja [Recuperar um limite](/pt/reference/tracer/retrieve-limit). O registro da decisão guarda o teto, o período e o escopo como estavam quando a decisão foi tomada, então um limite alterado depois disso não muda o que o registro diz.

Para como cada período conta e como o consumo acumula, veja [Limites de gasto](./spending-limits.mdx).

***

## Passo 5: Recupere o registro mais tarde

***

Cada decisão fica armazenada sob o seu `validationId`:

```http theme={null}
GET /v1/validations/8f14e45f-ea3b-4c6e-9a1c-2b7d5e0a91c4
X-API-Key: {api_key}
```

O registro responde com o contexto da transação que o Tracer avaliou — `transactionType`, `amount`, `currency`, `transactionTimestamp`, `account` e os opcionais `segment`, `portfolio`, `merchant` e `metadata` — mais os mesmos `decision`, `reason`, `matchedRuleIds`, `evaluatedRuleIds` e `limitUsageDetails` que a resposta original carregava, e um `createdAt`. Veja [Recuperar uma validação](/pt/reference/tracer/retrieve-validation).

Este é o registro para ler em voz alta numa disputa: é a entrada e o resultado em um só documento, e ele não muda quando regras ou limites mudam depois.

***

## Passo 6: Encontre registros quando você não tem o id

***

`GET /v1/validations` lista as decisões armazenadas, da mais recente para a mais antiga, com paginação por cursor:

```http theme={null}
GET /v1/validations?decision=DENY&account_id=550e8400-e29b-41d4-a716-446655440100&start_date=2026-07-01T00:00:00Z&end_date=2026-07-31T23:59:59Z
X-API-Key: {api_key}
```

<Warning>
  **Uma consulta sem datas cobre os últimos 90 dias, não todo o período de retenção.** O Tracer aplica essa janela padrão apenas quando tanto `start_date` quanto `end_date` estão ausentes. Envie uma das duas — ou ambas — para alcançar um intervalo mais antigo.
</Warning>

Dois filtros respondem às perguntas pelas quais este guia existe:

* `matched_rule_id={ruleId}` — toda decisão armazenada com a qual esta regra casou
* `exceeded_limit_id={limitId}` — toda decisão armazenada que este limite barrou

Cada resultado é um resumo: `validationId`, `decision`, `reason`, `amount`, `currency`, `transactionType`, `accountId`, `matchedRuleIds`, `exceededLimitIds`, `processingTimeMs` e `createdAt`. Pegue o `validationId` daquele que você quer e recupere-o com o Passo 5 para ter o registro completo. Veja [Listar validações](/pt/reference/tracer/list-validations) para todos os filtros e os campos de paginação.

***

## Passo 7: Puxe o evento de auditoria por trás da decisão

***

O rastro de auditoria registra a decisão com o `validationId` como `resourceId` do evento:

```http theme={null}
GET /v1/audit-events?resource_type=transaction&resource_id=8f14e45f-ea3b-4c6e-9a1c-2b7d5e0a91c4
X-API-Key: {api_key}
```

```json theme={null}
{
  "auditEvents": [
    {
      "hash": "a3f1e2b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2",
      "previousHash": "b4e2f3a5c6d7e8f9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3",
      "eventId": "1d0a6f52-7b3c-4e8d-9a01-5c2b6e7f8091",
      "eventType": "TRANSACTION_VALIDATED",
      "createdAt": "2026-07-31T14:05:09.492Z",
      "action": "VALIDATE",
      "result": "DENY",
      "resourceId": "8f14e45f-ea3b-4c6e-9a1c-2b7d5e0a91c4",
      "resourceType": "transaction",
      "actor": {
        "actorType": "api_key",
        "id": "tracer-default",
        "name": "",
        "ipAddress": "203.0.113.42"
      },
      "context": {
        "request": {
          "requestId": "7c3f1b8e-5a2d-4c6b-9e1f-0a4d8b2c6e30",
          "transactionType": "CARD",
          "amount": "1500",
          "currency": "BRL"
        },
        "response": {
          "decision": "DENY",
          "reason": "Rule matched with DENY action",
          "matchedRuleIds": [
            "3c8a5b21-9f4d-4e17-8b6a-1d2e3f405162"
          ],
          "evaluatedRuleIds": [
            "3c8a5b21-9f4d-4e17-8b6a-1d2e3f405162",
            "a6b7c8d9-0e1f-4a2b-9c3d-4e5f60718293"
          ],
          "totalRulesLoaded": 2,
          "truncated": false,
          "limitUsageDetails": [],
          "processingTimeMs": 9.4
        }
      }
    }
  ],
  "hasMore": false
}
```

O que o evento de auditoria acrescenta ao registro da validação:

| Campo              | Por que importa em uma revisão                                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `actor`            | Quem fez a chamada — a identidade por trás da requisição e o IP do cliente                                                                                               |
| `result`           | A decisão, indexada para filtrar, então `result=DENY` delimita uma consulta                                                                                              |
| `context.request`  | O snapshot da requisição registrado com a decisão                                                                                                                        |
| `context.response` | A decisão, o motivo e os identificadores de regras como foram devolvidos                                                                                                 |
| `eventId`          | A chave para o [Passo 8](#passo-8-verifique-o-evento-de-auditoria-em-uma-auditoria) e para [Recuperar um evento de auditoria](/pt/reference/tracer/retrieve-audit-event) |

<Warning>
  A janela padrão de 90 dias também vale aqui: `GET /v1/audit-events` sem `start_date` nem `end_date` cobre os últimos 90 dias. Envie o intervalo que você quer quando a decisão for mais antiga que isso.
</Warning>

O mesmo endpoint carrega o ciclo de vida de regras e limites — quem os criou, ativou ou deletou. Veja [Listar eventos de auditoria](/pt/reference/tracer/list-audit-events) para os filtros, e [Auditoria e compliance](./audit-compliance.mdx) para os tipos de evento e os períodos de retenção.

***

## Passo 8: Verifique o evento de auditoria em uma auditoria

***

Passe o `eventId` ao endpoint de verificação:

```http theme={null}
GET /v1/audit-events/1d0a6f52-7b3c-4e8d-9a01-5c2b6e7f8091/verify
X-API-Key: {api_key}
```

```json theme={null}
{
  "isValid": true,
  "totalChecked": 12345,
  "message": "Hash chain integrity verified successfully"
}
```

`isValid: true` estabelece que todo registro, do primeiro até aquele que você indicou, continua correspondendo ao hash armazenado com ele. Cada um também se liga ao hash do registro anterior, então dentro desse trecho nenhum registro foi removido, reordenado ou teve sua data alterada. `totalChecked` informa quantos registros a verificação cobriu.

Em uma verificação que falha, `isValid` é `false`, `message` informa a adulteração e `firstInvalidId` carrega um número de sequência interno do registro divergente. Esse número não é um id de evento de auditoria, então não é um valor para passar a `GET /v1/audit-events/{id}`.

Veja [Verificar um evento de auditoria](/pt/reference/tracer/verify-audit-event).

<Note>
  Entregue os dois juntos: o evento recuperado no Passo 7 é o conteúdo da decisão, e o resultado da verificação é a evidência de que a cadeia que o sustenta está intacta. A chamada de verificação informa sobre a cadeia — ela não devolve o registro.
</Note>

***

## Erros comuns

***

<Warning>
  **O que costuma dar errado em uma revisão:**

  * **"Minha consulta do ano passado voltou vazia."** Uma consulta sem `start_date` nem `end_date` cobre os últimos 90 dias. Envie o intervalo que você quer.
  * **"`matchedRuleIds` tem três entradas e só uma negou."** O array carrega toda regra que casou, qualquer que seja a ação que ela carrega. Recupere cada regra e leia sua `action` (Passo 3).
  * **"`limitUsageDetails` está vazio em uma negativa."** A decisão veio de uma regra, não de um limite. Leia `reason` (Passo 2).
  * **"`currentUsage` está maior do que o cliente gastou de fato."** É a cifra projetada, com o valor tentado já somado. Em um limite excedido o contador não foi incrementado, então o consumo armazenado não inclui esta transação.
  * **"A regra que disparou não existe mais."** Regras deletadas param de responder em `GET /v1/rules/{id}`. Consulte o ciclo de vida delas com `GET /v1/audit-events?resource_type=rule&resource_id={ruleId}`.
</Warning>

### Códigos de erro

| Código          | Status | O que mudar                                                                                    |
| --------------- | ------ | ---------------------------------------------------------------------------------------------- |
| `0065`          | 400    | O id no caminho não é um UUID                                                                  |
| `0432`          | 404    | Nenhuma validação armazenada tem esse `validationId`                                           |
| `0381`          | 404    | Nenhum evento de auditoria tem esse `eventId`                                                  |
| `0077`          | 400    | Uma data não está em RFC3339 com fuso horário — envie `2026-07-01T00:00:00Z`, não `2026-07-01` |
| `0083`          | 400    | `end_date` cai antes de `start_date`                                                           |
| `0431`          | 400    | Um filtro de `GET /v1/validations` carrega um valor que o endpoint não aceita                  |
| `0080` / `0331` | 400    | `limit` está acima de 1000, ou não é positivo                                                  |
| `0334`          | 400    | `cursor` foi enviado junto com `sort_by` ou `sort_order` — o cursor já os carrega              |

A lista completa está na [lista de erros do Tracer](/pt/reference/tracer/tracer-error-list).

***

## Referência rápida

***

| Passo                            | Método | Endpoint                       |
| -------------------------------- | ------ | ------------------------------ |
| Validar uma transação            | POST   | `/v1/validations`              |
| Encontrar decisões armazenadas   | GET    | `/v1/validations`              |
| Recuperar uma decisão            | GET    | `/v1/validations/{id}`         |
| Nomear uma regra                 | GET    | `/v1/rules/{id}`               |
| Nomear um limite                 | GET    | `/v1/limits/{id}`              |
| Encontrar eventos de auditoria   | GET    | `/v1/audit-events`             |
| Recuperar um evento de auditoria | GET    | `/v1/audit-events/{id}`        |
| Verificar a cadeia de hashes     | GET    | `/v1/audit-events/{id}/verify` |
