> ## 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 una transacción rechazada

> Lee una decisión DENY o REVIEW de Tracer para encontrar la regla o el límite detrás de ella, recupera el registro almacenado más tarde y verifica su evento de auditoría durante una auditoría.

export const GAuditTrail = ({children}) => <Tooltip headline="Registro de auditoría" tip="Un registro cronológico e inmutable de cada acción y transacción en el sistema, esencial para el cumplimiento normativo y la resolución de disputas." cta="Ver glosario" href="/es/start-here/glossary">
    {children}
  </Tooltip>;

Una validación regresó `DENY` o `REVIEW` y alguien pregunta por qué. Esta guía te lleva desde la decisión que devolvió Tracer hasta una regla identificada o un límite de gasto identificado. Desde ahí llega al registro almacenado y a la entrada del <GAuditTrail>registro de auditoría</GAuditTrail> que puedes entregar a un auditor meses después.

**Qué cambia en tu operación:** la respuesta a "¿por qué se bloqueó esto?" deja de ser una búsqueda en los registros. Cada decisión llega con los identificadores de lo que la produjo. El mismo registro responde por id años después, y puedes verificar su evento de auditoría contra la cadena de hashes.

<Tip>
  **¿Para quién es esta guía?** Desarrolladores que integran la llamada de validación, equipos de soporte y disputas que responden preguntas de clientes, y oficiales de cumplimiento que preparan evidencia. Los pasos 1 a 4 solo necesitan la respuesta que ya tienes. Los pasos 5 a 8 usan los endpoints de consulta.
</Tip>

## Antes de empezar

***

* [ ] Tracer en ejecución y accesible, con una clave de API. Consulta [Primeros pasos](./getting-started.mdx)
* [ ] Una respuesta `DENY` o `REVIEW` con la que trabajar, o el `validationId` de una
* [ ] Familiaridad con lo que hacen las reglas y los límites. Consulta [Motor de reglas](./rule-engine.mdx) y [Límites de gasto](./spending-limits.mdx)

Todas las llamadas siguientes envían la clave de API como `X-API-Key`.

***

## Paso 1: Leer la decisión que devolvió Tracer

***

`POST /v1/validations` responde con la decisión completa. Una solicitud nueva responde `201`. Un `requestId` repetido responde `200` con la decisión que Tracer ya registró para esa clave.

```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",
    "asset": "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"
    }
  }'
```

Un rechazo producido por una regla se ve así:

```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                              | Qué te indica                                                                                  |
| ---------------------------------- | ---------------------------------------------------------------------------------------------- |
| `validationId`                     | La clave de esta decisión. Todo lo que sigue en esta guía parte de este valor                  |
| `decision`                         | `ALLOW`, `DENY` o `REVIEW`                                                                     |
| `reason`                           | Qué produjo la decisión — consulta el [paso 2](#step-2-tell-a-rule-denial-from-a-limit-denial) |
| `matchedRuleIds`                   | Cada regla que coincidió con esta transacción, sin importar la acción que tenga                |
| `evaluatedRuleIds`                 | Las reglas que Tracer evaluó para esta transacción                                             |
| `limitUsageDetails`                | Una entrada por cada límite de gasto que Tracer verificó                                       |
| `totalRulesLoaded` / `truncated`   | Cuántas reglas se cargaron, y si `MAX_RULES_PER_REQUEST` recortó el conjunto                   |
| `processingTimeMs` / `evaluatedAt` | Cuánto tardó la evaluación, y cuándo se ejecutó                                                |

Para conocer el esquema completo de solicitud y respuesta, consulta [Validar una transacción](/es/reference/products/tracer/validate-transaction).

<Note>
  Guarda el `validationId` junto a tu propio registro de transacción. Es la clave que usa el [paso 5](#step-5-retrieve-the-record-later), y también es el `resourceId` del evento de auditoría en el [paso 7](#step-7-pull-the-audit-event-behind-the-decision).
</Note>

***

<h2 id="step-2-tell-a-rule-denial-from-a-limit-denial">
  Paso 2: Distinguir un rechazo por regla de un rechazo por límite
</h2>

***

Lee `reason` primero. Indica qué produjo la decisión, y te dice cuál de los dos pasos siguientes debes seguir.

| `reason`                        | Qué pasó                                                                        | Ir a                                                                                                |
| ------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `Rule matched with DENY action` | Coincidió una regla cuya acción es `DENY`                                       | [Paso 3](#step-3-name-the-rule)                                                                     |
| `limit_exceeded`                | El monto haría que un límite de gasto superara su techo                         | [Paso 4](#step-4-name-the-spending-limit)                                                           |
| `No matching rules found`       | Ninguna regla coincidió, así que Tracer aplicó `DEFAULT_DECISION_WHEN_NO_MATCH` | Revisa esa configuración en la página de [variables de entorno](./tracer-environment-variables.mdx) |

`reason` lleva el mismo texto en las decisiones `REVIEW` (`Rule matched with REVIEW action`), y el paso 3 lee una revisión de la misma forma en que lee un rechazo.

<Note>
  En un rechazo por regla, `limitUsageDetails` regresa vacío porque Tracer se detiene antes de la verificación de límites, no porque ningún límite aplique a la cuenta.
</Note>

***

<h2 id="step-3-name-the-rule">
  Paso 3: Identificar la regla
</h2>

***

`matchedRuleIds` enumera cada regla que coincidió, sin importar la acción que tenga cada una. Una regla `DENY` y una regla `ALLOW` pueden aparecer ambas en el mismo rechazo. Recupera cada una y lee su `action` para encontrar la regla detrás de la decisión:

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

La regla lleva el `name`, `description`, `expression`, `action` y `scopes` que un colega necesita para ver por qué se activó. Consulta [Recuperar una regla](/es/reference/products/tracer/retrieve-rule).

Compara `matchedRuleIds` con `evaluatedRuleIds` cuando la pregunta es la opuesta: "¿por qué mi regla *no* se activó?". Tracer no evaluó una regla que esté ausente de `evaluatedRuleIds`. Empieza por su estado y su alcance en lugar de su expresión.

<Tip>
  Una regla eliminada después de la decisión ya no responde en `GET /v1/rules/{id}`. Su historial, incluido quién la eliminó, permanece en el registro de auditoría. Consulta [Auditoría y cumplimiento](./audit-compliance.mdx).
</Tip>

***

<h2 id="step-4-name-the-spending-limit">
  Paso 4: Identificar el límite de gasto
</h2>

***

En un rechazo por `limit_exceeded`, `limitUsageDetails` contiene una entrada por cada límite que Tracer verificó, y las entradas marcadas con `"exceeded": true` son las que el monto superaría:

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

Lee la entrada superada como la aritmética del rechazo: `attemptedAmount` contra `limitAmount`. El campo `currentUsage` informa lo que el período actual y el alcance coincidente de ese límite contendrían si se incluyera esta transacción. En la entrada anterior, una compra de `1500` llevaría un tope diario de `50000` a `51500`.

Un límite `PER_TRANSACTION` no lleva ningún conteo, así que su entrada informa `currentUsage` como `0`, y `attemptedAmount` contra `limitAmount` es toda la comparación.

`GET /v1/limits/{limitId}` da el nombre y la configuración actuales del límite. Consulta [Recuperar un límite](/es/reference/products/tracer/retrieve-limit). El registro de la decisión conserva el techo, el período y el alcance que aplicaban cuando Tracer tomó la decisión. Un límite modificado después no cambia lo que dice el registro.

Para saber cómo cuenta cada período y cómo se acumula el consumo, consulta [Límites de gasto](./spending-limits.mdx).

***

<h2 id="step-5-retrieve-the-record-later">
  Paso 5: Recuperar el registro más tarde
</h2>

***

Tracer almacena cada decisión bajo su `validationId`:

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

El registro responde con el contexto de la transacción que Tracer evaluó (`transactionType`, `amount`, `asset`, `transactionTimestamp`, `account`, y los campos opcionales `segment`, `portfolio`, `merchant` y `metadata`), además de los mismos `decision`, `reason`, `matchedRuleIds`, `evaluatedRuleIds` y `limitUsageDetails` que llevaba la respuesta original, y un `createdAt`. Consulta [Recuperar una validación](/es/reference/products/tracer/retrieve-validation).

Presenta este registro en una disputa. Contiene la entrada y el resultado en un solo documento. No cambia cuando las reglas o los límites cambian después.

***

## Paso 6: Encontrar registros cuando no tienes el id

***

`GET /v1/validations` enumera las decisiones almacenadas, de la más reciente a la más antigua, con paginación 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>
  **Una consulta sin fechas cubre los últimos 90 días, no todo el período de retención.** Tracer aplica esa ventana predeterminada solo cuando faltan tanto `start_date` como `end_date`. Envía uno de los dos, o ambos, para llegar a un rango más antiguo.
</Warning>

Dos filtros responden las preguntas para las que existe esta guía:

* `matched_rule_id={ruleId}`: cada decisión almacenada con la que esta regla coincidió
* `exceeded_limit_id={limitId}`: cada decisión almacenada que este límite detuvo

Cada resultado es un resumen: `validationId`, `decision`, `reason`, `amount`, `asset`, `transactionType`, `accountId`, `matchedRuleIds`, `exceededLimitIds`, `processingTimeMs` y `createdAt`. Toma el `validationId` del que quieres y recupéralo con el paso 5 para obtener el registro completo. Consulta [Listar validaciones](/es/reference/products/tracer/list-validations) para conocer todos los filtros y los campos de paginación.

***

<h2 id="step-7-pull-the-audit-event-behind-the-decision">
  Paso 7: Obtener el evento de auditoría detrás de la decisión
</h2>

***

El registro de auditoría almacena la decisión bajo el `validationId` como el `resourceId` del 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",
          "asset": "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
}
```

Lo que el evento de auditoría agrega al registro de validación:

| Campo              | Por qué importa en una revisión                                                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actor`            | Quién hizo la llamada — la identidad detrás de la solicitud, y la IP del cliente                                                                                    |
| `result`           | La decisión, indexada para filtrar, de modo que `result=DENY` acota una consulta                                                                                    |
| `context.request`  | La instantánea de la solicitud registrada con la decisión                                                                                                           |
| `context.response` | La decisión, la razón y los identificadores de regla tal como se devolvieron                                                                                        |
| `eventId`          | La clave para el [paso 8](#step-8-verify-the-audit-event-in-an-audit) y para [Recuperar un evento de auditoría](/es/reference/products/tracer/retrieve-audit-event) |

<Warning>
  La ventana predeterminada de 90 días también aplica aquí: `GET /v1/audit-events` sin `start_date` ni `end_date` cubre los últimos 90 días. Envía el rango que quieras cuando la decisión sea más antigua que eso.
</Warning>

El mismo endpoint lleva el ciclo de vida de las reglas y los límites: quién los creó, activó o eliminó. Consulta [Listar eventos de auditoría](/es/reference/products/tracer/list-audit-events) para conocer los filtros, y [Auditoría y cumplimiento](./audit-compliance.mdx) para los tipos de evento y los períodos de retención.

***

<h2 id="step-8-verify-the-audit-event-in-an-audit">
  Paso 8: Verificar el evento de auditoría en una auditoría
</h2>

***

Pasa el `eventId` al endpoint de verificación:

```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` establece que cada registro desde el primero hasta el que nombraste sigue coincidiendo con el hash almacenado junto a él. Cada uno también enlaza con el hash del registro anterior. Dentro de ese tramo, ningún registro fue eliminado, reordenado ni refechado. `totalChecked` informa cuántos registros cubrió la verificación.

En una verificación fallida, `isValid` es `false`, `message` informa manipulación, y `firstInvalidId` lleva un número de secuencia interno para el registro divergente. Ese número no es un id de evento de auditoría, así que no es un valor para pasar a `GET /v1/audit-events/{id}`.

Consulta [Verificar un evento de auditoría](/es/reference/products/tracer/verify-audit-event).

<Note>
  Entrega los dos juntos: el evento recuperado en el paso 7 es el contenido de la decisión, y el resultado de la verificación es la evidencia de que la cadena que lo contiene está intacta. La llamada de verificación informa sobre la cadena. No devuelve el registro.
</Note>

***

## Errores comunes

***

<Warning>
  **Lo que suele salir mal en una revisión:**

  * **"Mi consulta del año pasado regresó vacía."** Una consulta sin `start_date` ni `end_date` cubre los últimos 90 días. Envía el rango que quieres.
  * **"`matchedRuleIds` tiene tres entradas y solo una rechazó."** El arreglo contiene cada regla que coincidió, sin importar la acción que lleve. Recupera cada regla y lee su `action` (paso 3).
  * **"`limitUsageDetails` está vacío en un rechazo."** La decisión vino de una regla, no de un límite. Lee `reason` (paso 2).
  * **"`currentUsage` es mayor que lo que el cliente realmente gastó."** Ya incluye el monto intentado, así que es una proyección. En un límite superado el contador se mantiene igual, así que el consumo almacenado no incluye esta transacción.
  * **"La regla que se activó ya no existe."** Las reglas eliminadas dejan de responder en `GET /v1/rules/{id}`. Consulta su ciclo de vida mediante `GET /v1/audit-events?resource_type=rule&resource_id={ruleId}`.
</Warning>

### Códigos de error

| Código          | Estado | Qué cambiar                                                                                   |
| --------------- | ------ | --------------------------------------------------------------------------------------------- |
| `0065`          | 400    | El id en la ruta no es un UUID                                                                |
| `0432`          | 404    | Ninguna validación almacenada tiene ese `validationId`                                        |
| `0381`          | 404    | Ningún evento de auditoría tiene ese `eventId`                                                |
| `0077`          | 400    | Una fecha no está en RFC3339 con zona horaria — envía `2026-07-01T00:00:00Z`, no `2026-07-01` |
| `0083`          | 400    | `end_date` es anterior a `start_date`                                                         |
| `0431`          | 400    | Un filtro en `GET /v1/validations` lleva un valor que el endpoint no acepta                   |
| `0080` / `0331` | 400    | `limit` es mayor que 1000, o no es positivo                                                   |
| `0334`          | 400    | `cursor` se envió junto con `sort_by` o `sort_order` — el cursor ya los lleva                 |

La lista completa está en [Lista de errores de Tracer](/es/reference/products/tracer/tracer-error-list).

***

## Referencia rápida

***

| Paso                             | Método | Endpoint                       |
| -------------------------------- | ------ | ------------------------------ |
| Validar una transacción          | POST   | `/v1/validations`              |
| Encontrar decisiones almacenadas | GET    | `/v1/validations`              |
| Recuperar una decisión           | GET    | `/v1/validations/{id}`         |
| Identificar una regla            | GET    | `/v1/rules/{id}`               |
| Identificar un límite            | GET    | `/v1/limits/{id}`              |
| Encontrar eventos de auditoría   | GET    | `/v1/audit-events`             |
| Recuperar un evento de auditoría | GET    | `/v1/audit-events/{id}`        |
| Verificar la cadena de hashes    | GET    | `/v1/audit-events/{id}/verify` |
