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

# Configurar un límite de gasto

> Limita lo que una cuenta, un portafolio o un segmento puede gastar en un período con Tracer, activa el tope y lee cuánto queda desde la decisión de validación.

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>;

Una decisión de producto o de riesgo llegó como una frase: "no más de R\$ 20.000 por cuenta al mes". Esta guía convierte esa frase en un tope activo y muestra dónde leer cuánto le queda a un cliente.

**Lo que cambia en tu operación:** el techo deja de ser una constante compilada en un servicio. Pasa a ser una definición almacenada que creas, activas, subes y detienes — y cada decisión que lo toca informa lo que consumió.

<Tip>
  **¿Para quién es esta guía?** Equipos de producto y de riesgo que fijan el techo, y desarrolladores que integran `POST /v1/validations` en el flujo de pago. Los pasos 1 y 2 son decisiones que tomas antes de cualquier llamada; los pasos 3 a 6 son las llamadas.
</Tip>

## Antes de empezar

***

* [ ] Tracer en ejecución y alcanzable, con una API key — consulta [Primeros pasos](./getting-started.mdx)
* [ ] El id de la cuenta, el portafolio o el segmento al que aplica el tope
* [ ] La moneda de las transacciones que quieres limitar
* [ ] Familiaridad con los tipos de límite, las ventanas de tiempo y los períodos personalizados — consulta [Límites de gasto](./spending-limits.mdx)

Todas las llamadas de abajo envían la API key como `X-API-Key` y corren contra `http://localhost:4020`.

***

## Paso 1: Decide a qué se dirige el tope

***

Un límite lleva una lista de objetos de alcance, y cada objeto nombra a qué aplica el límite. Estos campos están disponibles dentro de un objeto:

| Campo             | Aplica el límite a                                                                |
| ----------------- | --------------------------------------------------------------------------------- |
| `accountId`       | Transacciones de una cuenta                                                       |
| `portfolioId`     | Transacciones de un portafolio                                                    |
| `segmentId`       | Transacciones de un segmento                                                      |
| `merchantId`      | Transacciones hacia un comercio                                                   |
| `transactionType` | Uno de `CARD`, `WIRE`, `PIX`, `CRYPTO`                                            |
| `subType`         | Un subtipo de transacción, como `purchase` — se compara sin distinguir mayúsculas |

Los campos dentro de un objeto se combinan con AND. Un campo que dejas fuera es un comodín. Entre objetos la lista se combina con OR, así que un límite con dos objetos aplica cuando cualquiera de los dos coincide.

La elección que decide la respuesta a "R\$ 20.000 por cuenta" es **qué id nombras**:

<Tabs>
  <Tab title="Una cuenta, su propio presupuesto">
    ```json theme={null}
    "scopes": [
      { "accountId": "550e8400-e29b-41d4-a716-446655440100" }
    ]
    ```

    El tope se dirige a esa cuenta. Cuenta el gasto de esa cuenta y de ninguna otra. Para un techo por cuenta sobre una cartera de clientes, cada cuenta recibe su propio límite.
  </Tab>

  <Tab title="Un segmento, un presupuesto compartido">
    ```json theme={null}
    "scopes": [
      { "segmentId": "2f1c9b7e-40a5-4d18-9c6b-3e7f5a0d1b24" }
    ]
    ```

    El tope se dirige al segmento entero. Cada cuenta de ese segmento consume los mismos R\$ 20.000 — los primeros clientes en gastar lo agotan para el resto.
  </Tab>

  <Tab title="Restringido a un solo riel">
    ```json theme={null}
    "scopes": [
      {
        "accountId": "550e8400-e29b-41d4-a716-446655440100",
        "transactionType": "PIX"
      }
    ]
    ```

    El tope cuenta solo las transacciones Pix de esa cuenta. Su tráfico de tarjeta y de transferencia pasa sin tocar este límite.
  </Tab>
</Tabs>

<Note>
  Un límite también lleva una `currency`, y Tracer comprueba un límite contra una transacción solo cuando las dos coinciden. Un límite creado en `BRL` no se comprueba contra una transacción en `USD`, así que una cartera que liquida en dos monedas necesita un límite para cada una.
</Note>

Un límite debe llevar al menos un objeto de alcance, y cada objeto debe fijar al menos un campo. Una lista vacía, o un objeto vacío, se rechaza — consulta [Qué sale mal](#qué-sale-mal).

***

## Paso 2: Elige el período

***

`limitType` decide tanto el tamaño de la ventana del techo como cuándo empieza un nuevo conteo. Tracer ofrece cinco:

| `limitType`       | El conteo cubre                 | Un nuevo conteo empieza                                   |
| ----------------- | ------------------------------- | --------------------------------------------------------- |
| `DAILY`           | Un día calendario, UTC          | Cada día a las 00:00 UTC                                  |
| `WEEKLY`          | Una semana ISO, UTC             | Cada lunes a las 00:00 UTC                                |
| `MONTHLY`         | Un mes calendario, UTC          | El día 1 a las 00:00 UTC                                  |
| `CUSTOM`          | Un rango de fechas que tú fijas | Nunca — un solo conteo cubre todo el rango                |
| `PER_TRANSACTION` | Una sola transacción            | No se guarda conteo; cada transacción se mide por sí sola |

"al mes" es `MONTHLY`.

<Warning>
  **El límite del período es UTC, no la hora local.** Un cliente de São Paulo que gasta a las 21:30 del 31 de julio está a las 00:30 UTC del 1 de agosto, así que ese importe cae en el conteo de agosto, no en el de julio. Cuando un tope se acuerda en términos locales, espera que las últimas horas del mes local pertenezcan al siguiente.
</Warning>

`CUSTOM` toma `customStartDate` y `customEndDate` y es la forma para una campaña o una promoción. Esos dos campos pertenecen a `CUSTOM` y se rechazan en los otros cuatro tipos. Para restringir un tope a ciertas horas del día, consulta las [ventanas de tiempo](./spending-limits.mdx#ventanas-de-tiempo).

***

## Paso 3: Crea el límite

***

`POST /v1/limits` almacena la definición. Se crea en `DRAFT`, lo que significa que está almacenada pero todavía no se comprueba.

```bash theme={null}
curl -X POST http://localhost:4020/v1/limits \
  -H "X-API-Key: your-secure-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Tope mensual por cuenta",
    "description": "Limita la salida mensual total de una cuenta",
    "limitType": "MONTHLY",
    "maxAmount": "20000.00",
    "currency": "BRL",
    "scopes": [
      { "accountId": "550e8400-e29b-41d4-a716-446655440100" }
    ]
  }'
```

Una llamada exitosa responde `201`. El cuerpo es el límite almacenado; dos campos importan ahora:

| Campo     | Qué hacer con él                                                                      |
| --------- | ------------------------------------------------------------------------------------- |
| `limitId` | El id que toma cada llamada posterior de esta guía. Guárdalo                          |
| `status`  | `DRAFT` — el límite todavía no se comprueba. El [paso 4](#paso-4-actívalo) cambia eso |

<Note>
  **Los nombres son únicos entre límites, y el conjunto de caracteres es estrecho.** `name` acepta letras y dígitos ASCII, espacios y `-`, `_`, `.`, `(`, `)`. Un acento o un guion escrito como raya se rechaza con `0371`. Un nombre que ya tiene otro límite vigente se rechaza con `0442`; eliminar un límite libera su nombre de nuevo.
</Note>

Para la carga completa y cada campo opcional, consulta [Crear un límite](/es/reference/tracer/create-limit).

***

## Paso 4: Actívalo

***

Un límite en `DRAFT` no se comprueba. La activación es lo que lo pone en el camino:

```bash theme={null}
curl -X POST http://localhost:4020/v1/limits/{limitId}/activate \
  -H "X-API-Key: your-secure-api-key"
```

La respuesta lleva el límite con `status` en `ACTIVE`. Desde aquí, cada `POST /v1/validations` cuya transacción coincida con el alcance y la moneda se mide contra él.

<Note>
  **Activar a mitad de mes no importa la historia del mes.** Tracer cuenta una transacción contra un límite en el momento en que decide sobre ella, así que el gasto ocurrido mientras el límite estaba en `DRAFT` no está en el conteo. Un tope activado el día 20 gobierna lo que pasa del 20 en adelante.
</Note>

Consulta [Activar un límite](/es/reference/tracer/activate-limit).

***

## Paso 5: Lee cuánto queda

***

Cada respuesta de `POST /v1/validations` lleva `limitUsageDetails`, con una entrada por cada límite que Tracer comprobó:

```json theme={null}
{
  "limitId": "b2d4f6a8-1c3e-4507-9b8d-6f0a2c4e6810",
  "limitAmount": "20000",
  "scope": "(account:550e8400-e29b-41d4-a716-446655440100)",
  "period": "MONTHLY",
  "currentUsage": "20000",
  "attemptedAmount": "1500",
  "exceeded": false
}
```

| Campo             | Qué informa                                                                                                       |
| ----------------- | ----------------------------------------------------------------------------------------------------------------- |
| `limitAmount`     | El techo que se comprobó                                                                                          |
| `currentUsage`    | El consumo proyectado del período actual de ese límite y del alcance que coincidió si esta transacción se permite |
| `attemptedAmount` | El importe medido contra el techo                                                                                 |
| `period`          | El tipo del límite — aquí `MONTHLY`                                                                               |
| `scope`           | El alcance del límite como texto, cada objeto entre paréntesis, varios objetos unidos por `OR`                    |
| `exceeded`        | Si el importe llevaría este tope más allá de su techo                                                             |

En la entrada de arriba, una compra de R\$ 1.500 llevó un mes de 18.500 a exactamente 20.000 — el tope está agotado, y la siguiente transacción de esa cuenta se deniega hasta agosto.

Cuando se supera un límite, la decisión es `DENY` y `reason` es `limit_exceeded`; el importe que habría cruzado el techo no se suma al conteo. Un límite produce una denegación, no una marca para revisión. Para ir desde esa denegación de vuelta al límite que la causó, consulta [Revisar una transacción denegada](./reviewing-a-denied-transaction.mdx).

### La otra lectura

`GET /v1/limits/{limitId}/usage` responde con un total del límite en lugar de un total de un período: suma los contadores de uso registrados contra él, entre los períodos y alcances que ha acumulado. Úsalo para revisar cuánto ha absorbido un límite en total — no para responder cuánto le queda a un cliente este mes.

Un contador se elimina 90 días después de que termina su período, así que en un límite de larga duración este total cubre solo los períodos aún conservados, no toda la vida del límite. Consulta [Seguimiento de uso](./spending-limits.mdx#seguimiento-de-uso).

Consulta [Recuperar el uso de un límite](/es/reference/tracer/retrieve-limit-usage).

***

## Paso 6: Cámbialo, páusalo, quítalo

***

<Steps>
  <Step title="Sube o baja el techo">
    ```bash theme={null}
    curl -X PATCH http://localhost:4020/v1/limits/{limitId} \
      -H "X-API-Key: your-secure-api-key" \
      -H "Content-Type: application/json" \
      -d '{ "maxAmount": "30000.00" }'
    ```

    `name`, `description`, `maxAmount` y `scopes` son editables, y también lo son los campos de ventana de tiempo y de período personalizado. `limitType` y `currency` no lo son — una solicitud que envía cualquiera de los dos se rechaza con `0380`, y un período o una moneda distintos significan un límite nuevo. Un cuerpo sin nada dentro se rechaza con `0183`. Consulta [Actualizar un límite](/es/reference/tracer/update-limit).

    Cambiar el techo no borra el conteo en curso. Bájalo por debajo de lo que el período actual ya consumió y la cuenta queda denegada hasta que empiece el período siguiente.
  </Step>

  <Step title="Detén la aplicación">
    ```bash theme={null}
    curl -X POST http://localhost:4020/v1/limits/{limitId}/deactivate \
      -H "X-API-Key: your-secure-api-key"
    ```

    El límite pasa a `INACTIVE` y deja de comprobarse. Conserva su definición y su lugar en el <GAuditTrail>rastro de auditoría</GAuditTrail>, y `POST /v1/limits/{limitId}/activate` lo devuelve al camino. Consulta [Desactivar un límite](/es/reference/tracer/deactivate-limit).
  </Step>

  <Step title="Devuélvelo a borrador">
    ```bash theme={null}
    curl -X POST http://localhost:4020/v1/limits/{limitId}/draft \
      -H "X-API-Key: your-secure-api-key"
    ```

    Devuelve un límite `INACTIVE` a `DRAFT`. Consulta [Devolver un límite a borrador](/es/reference/tracer/draft-limit).
  </Step>

  <Step title="Quítalo">
    ```bash theme={null}
    curl -X DELETE http://localhost:4020/v1/limits/{limitId} \
      -H "X-API-Key: your-secure-api-key"
    ```

    Responde `204`. Un límite que está `ACTIVE` tiene que desactivarse primero — Tracer rechaza la eliminación con `0363`, que es lo que impide que un techo vigente desaparezca por accidente. Consulta [Eliminar un límite](/es/reference/tracer/delete-limit).
  </Step>
</Steps>

### Encuentra los límites que ya tienes

`GET /v1/limits` los lista, y filtra por los mismos campos de alcance que fijaste en el paso 1:

```http theme={null}
GET /v1/limits?status=ACTIVE&account_id=550e8400-e29b-41d4-a716-446655440100&limit_type=MONTHLY
X-API-Key: {api_key}
```

`name`, `status`, `limit_type`, `account_id`, `segment_id`, `portfolio_id`, `merchant_id`, `transaction_type` y `sub_type` filtran; los resultados se paginan con cursor. Consulta [Listar límites](/es/reference/tracer/list-limits), y [Recuperar un límite](/es/reference/tracer/retrieve-limit) para uno por id.

***

## Qué sale mal

***

<Warning>
  **Lo que suele salir mal al configurar un tope:**

  * **"El cliente se pasó y nada lo detuvo."** Revisa primero `status` — un límite en `DRAFT` o `INACTIVE` no se comprueba. Después revisa que la `currency` del límite coincida con la de la transacción, y que el alcance nombre el id que la transacción realmente llevaba.
  * **"El tope del segmento se agotó el segundo día."** Un límite con alcance de segmento es un presupuesto para todo el segmento, no uno por cada cuenta dentro de él. Un techo por cuenta significa un límite dirigido a cada cuenta.
  * **"El mes cambió unas horas antes."** Los límites de período son UTC. El gasto después de las 21:00 en UTC-3 pertenece al día UTC siguiente, y el último día del mes, al mes siguiente.
  * **"Subí el límite y la cuenta sigue denegada."** Subir el techo no borra el conteo. Confirma que el nuevo `maxAmount` esté por encima de lo que el período ya consumió.
  * **"`GET /v1/limits/{id}/usage` informa más de lo que el cliente gastó este mes."** Ese endpoint totaliza los contadores registrados para el límite, entre períodos y alcances. Para el período actual, lee `limitUsageDetails` en la respuesta de validación.
</Warning>

### Códigos de error

| Código | Estado | Qué cambiar                                                                                                                                                                                    |
| ------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0009` | 400    | Un campo falló la validación — `detail` lo nombra, por ejemplo `scopes must have at least 1 item(s)`, `scope at index 0 must have at least one field set` o `maxAmount must be greater than 0` |
| `0065` | 400    | El id de la ruta no es un UUID                                                                                                                                                                 |
| `0183` | 400    | El cuerpo del `PATCH` no llevaba ningún campo editable                                                                                                                                         |
| `0362` | 404    | Ningún límite tiene ese id                                                                                                                                                                     |
| `0363` | 422    | La transición no está permitida — eliminar un límite `ACTIVE`, por ejemplo                                                                                                                     |
| `0366` | 400    | `currency` son tres letras mayúsculas pero no un código ISO 4217                                                                                                                               |
| `0371` | 400    | `name` lleva un carácter que el campo no acepta                                                                                                                                                |
| `0380` | 422    | La solicitud intentó cambiar `limitType` o `currency`                                                                                                                                          |
| `0442` | 409    | Otro límite vigente ya tiene ese nombre                                                                                                                                                        |

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

***

## Referencia rápida

***

| Paso                               | Método | Endpoint                         |
| ---------------------------------- | ------ | -------------------------------- |
| Crear un límite                    | POST   | `/v1/limits`                     |
| Activarlo                          | POST   | `/v1/limits/{id}/activate`       |
| Leer el consumo con la decisión    | POST   | `/v1/validations`                |
| Leer el total acumulado del límite | GET    | `/v1/limits/{id}/usage`          |
| Cambiar el techo                   | PATCH  | `/v1/limits/{id}`                |
| Detener la aplicación              | POST   | `/v1/limits/{id}/deactivate`     |
| Devolverlo a borrador              | POST   | `/v1/limits/{id}/draft`          |
| Quitarlo                           | DELETE | `/v1/limits/{id}`                |
| Encontrar límites                  | GET    | `/v1/limits` · `/v1/limits/{id}` |
