> ## 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 um limite de gasto

> Limite quanto uma conta, um portfólio ou um segmento pode gastar em um período com o Tracer, ative o teto e leia quanto sobrou na decisão de validação.

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 decisão de produto ou de risco chegou como uma frase: "no máximo R\$ 20.000 por conta por mês". Este guia transforma essa frase em um teto ativo e mostra onde ler quanto ainda resta para um cliente.

**O que muda na sua operação:** o teto deixa de ser uma constante compilada dentro de um serviço. Passa a ser uma definição armazenada que você cria, ativa, aumenta e interrompe — e cada decisão que encosta nele informa o quanto consumiu.

<Tip>
  **Para quem é este guia?** Times de produto e de risco que definem o teto, e desenvolvedores que integram `POST /v1/validations` no caminho do pagamento. Os passos 1 e 2 são decisões que você toma antes de qualquer chamada; os passos 3 a 6 são as chamadas.
</Tip>

## Antes de começar

***

* [ ] Tracer em execução e acessível, com uma API key — veja [Primeiros passos](./getting-started.mdx)
* [ ] O id da conta, do portfólio ou do segmento a que o teto se aplica
* [ ] A moeda das transações que você quer limitar
* [ ] Familiaridade com os tipos de limite, as janelas de tempo e os períodos personalizados — veja [Limites de gasto](./spending-limits.mdx)

Todas as chamadas abaixo enviam a API key como `X-API-Key` e rodam contra `http://localhost:4020`.

***

## Passo 1: Decida a que o teto se dirige

***

Um limite carrega uma lista de objetos de escopo, e cada objeto nomeia a que o limite se aplica. Estes campos ficam disponíveis dentro de um objeto:

| Campo             | Aplica o limite a                                                               |
| ----------------- | ------------------------------------------------------------------------------- |
| `accountId`       | Transações de uma conta                                                         |
| `portfolioId`     | Transações de um portfólio                                                      |
| `segmentId`       | Transações de um segmento                                                       |
| `merchantId`      | Transações para um estabelecimento                                              |
| `transactionType` | Um de `CARD`, `WIRE`, `PIX`, `CRYPTO`                                           |
| `subType`         | Um subtipo de transação, como `purchase` — comparado sem diferenciar maiúsculas |

Os campos dentro de um objeto se combinam com AND. Um campo que você deixa de fora é um curinga. Entre objetos a lista se combina com OR, então um limite com dois objetos se aplica quando qualquer um dos dois casa.

A escolha que decide a resposta para "R\$ 20.000 por conta" é **qual id você nomeia**:

<Tabs>
  <Tab title="Uma conta, o próprio orçamento">
    ```json theme={null}
    "scopes": [
      { "accountId": "550e8400-e29b-41d4-a716-446655440100" }
    ]
    ```

    O teto se dirige àquela conta. Ele conta o gasto daquela conta e de nenhuma outra. Para um teto por conta em toda uma carteira de clientes, cada conta ganha o próprio limite.
  </Tab>

  <Tab title="Um segmento, um orçamento compartilhado">
    ```json theme={null}
    "scopes": [
      { "segmentId": "2f1c9b7e-40a5-4d18-9c6b-3e7f5a0d1b24" }
    ]
    ```

    O teto se dirige ao segmento inteiro. Toda conta daquele segmento consome os mesmos R\$ 20.000 — os primeiros clientes a gastar o esgotam para os demais.
  </Tab>

  <Tab title="Restrito a um único trilho">
    ```json theme={null}
    "scopes": [
      {
        "accountId": "550e8400-e29b-41d4-a716-446655440100",
        "transactionType": "PIX"
      }
    ]
    ```

    O teto conta apenas as transações Pix daquela conta. O tráfego de cartão e de transferência dela passa sem encostar neste limite.
  </Tab>
</Tabs>

<Note>
  Um limite também carrega uma `currency`, e o Tracer confere um limite contra uma transação apenas quando as duas coincidem. Um limite criado em `BRL` não é conferido contra uma transação em `USD`, então uma carteira que liquida em duas moedas precisa de um limite para cada uma.
</Note>

Um limite precisa carregar pelo menos um objeto de escopo, e cada objeto precisa definir pelo menos um campo. Uma lista vazia, ou um objeto vazio, é recusada — veja [O que dá errado](#o-que-dá-errado).

***

## Passo 2: Escolha o período

***

`limitType` decide tanto o tamanho da janela do teto quanto quando uma nova contagem começa. O Tracer oferece cinco:

| `limitType`       | A contagem cobre                      | Uma nova contagem começa                                     |
| ----------------- | ------------------------------------- | ------------------------------------------------------------ |
| `DAILY`           | Um dia do calendário, UTC             | Todo dia às 00:00 UTC                                        |
| `WEEKLY`          | Uma semana ISO, UTC                   | Toda segunda-feira às 00:00 UTC                              |
| `MONTHLY`         | Um mês do calendário, UTC             | No dia 1º às 00:00 UTC                                       |
| `CUSTOM`          | Um intervalo de datas que você define | Nunca — uma única contagem cobre o intervalo inteiro         |
| `PER_TRANSACTION` | Uma única transação                   | Nenhuma contagem é guardada; cada transação é medida sozinha |

"por mês" é `MONTHLY`.

<Warning>
  **A virada do período é em UTC, não no horário local.** Um cliente de São Paulo que gasta às 21:30 de 31 de julho está às 00:30 UTC de 1º de agosto, então aquele valor cai na contagem de agosto, não na de julho. Quando um teto é acordado em termos locais, espere que as últimas horas do mês local pertençam ao mês seguinte.
</Warning>

`CUSTOM` recebe `customStartDate` e `customEndDate` e é o formato para uma campanha ou uma promoção. Esses dois campos pertencem ao `CUSTOM` e são recusados nos outros quatro tipos. Para restringir um teto a certas horas do dia, veja as [janelas de tempo](./spending-limits.mdx#janelas-de-tempo).

***

## Passo 3: Crie o limite

***

`POST /v1/limits` armazena a definição. Ela nasce em `DRAFT`, o que significa que está armazenada mas ainda não é conferida.

```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": "Limite mensal por conta",
    "description": "Limita a saída mensal total de uma conta",
    "limitType": "MONTHLY",
    "maxAmount": "20000.00",
    "currency": "BRL",
    "scopes": [
      { "accountId": "550e8400-e29b-41d4-a716-446655440100" }
    ]
  }'
```

Uma chamada bem-sucedida responde `201`. O corpo é o limite armazenado; dois campos importam agora:

| Campo     | O que fazer com ele                                                               |
| --------- | --------------------------------------------------------------------------------- |
| `limitId` | O id que cada chamada seguinte deste guia recebe. Guarde                          |
| `status`  | `DRAFT` — o limite ainda não é conferido. O [passo 4](#passo-4-ative-o) muda isso |

<Note>
  **Os nomes são únicos entre limites, e o conjunto de caracteres é estreito.** `name` aceita letras e dígitos ASCII, espaços e `-`, `_`, `.`, `(`, `)`. Um acento ou um travessão é recusado com `0371`. Um nome que outro limite vigente já ocupa é recusado com `0442`; excluir um limite libera o nome dele de novo.
</Note>

Para a carga completa e cada campo opcional, veja [Criar um limite](/pt/reference/tracer/create-limit).

***

## Passo 4: Ative-o

***

Um limite em `DRAFT` não é conferido. A ativação é o que o coloca no caminho:

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

A resposta traz o limite com `status` em `ACTIVE`. A partir daqui, todo `POST /v1/validations` cuja transação case com o escopo e a moeda é medido contra ele.

<Note>
  **Ativar no meio do mês não importa o histórico do mês.** O Tracer conta uma transação contra um limite no momento em que decide sobre ela, então o gasto que aconteceu enquanto o limite estava em `DRAFT` não está na contagem. Um teto ativado no dia 20 governa o que acontece do dia 20 em diante.
</Note>

Veja [Ativar um limite](/pt/reference/tracer/activate-limit).

***

## Passo 5: Leia quanto ainda resta

***

Toda resposta de `POST /v1/validations` traz `limitUsageDetails`, com uma entrada por limite que o Tracer conferiu:

```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             | O que informa                                                                                             |
| ----------------- | --------------------------------------------------------------------------------------------------------- |
| `limitAmount`     | O teto que foi conferido                                                                                  |
| `currentUsage`    | O consumo projetado do período atual daquele limite e do escopo que casou se esta transação for permitida |
| `attemptedAmount` | O valor medido contra o teto                                                                              |
| `period`          | O tipo do limite — aqui `MONTHLY`                                                                         |
| `scope`           | O escopo do limite como texto, cada objeto entre parênteses, vários objetos unidos por `OR`               |
| `exceeded`        | Se o valor levaria este teto além do seu limite                                                           |

Na entrada acima, uma compra de R\$ 1.500 levou um mês de 18.500 a exatamente 20.000 — o teto está esgotado, e a próxima transação daquela conta é negada até agosto.

Quando um limite é ultrapassado, a decisão é `DENY` e `reason` é `limit_exceeded`; o valor que teria cruzado o teto não entra na contagem. Um limite produz uma negativa, não uma marcação para revisão. Para ir dessa negativa de volta ao limite que a causou, veja [Revisar uma transação negada](./reviewing-a-denied-transaction.mdx).

### A outra leitura

`GET /v1/limits/{limitId}/usage` responde com um total do limite, não com o total de um período: ele soma os contadores de uso registrados contra o limite, entre os períodos e escopos que ele acumulou. Use para revisar quanto um limite absorveu no total — não para responder quanto sobra para um cliente neste mês.

Um contador é removido 90 dias após o fim do seu período, então em um limite de longa duração esse total cobre apenas os períodos ainda conservados, não a vida inteira do limite. Veja [Rastreamento de uso](./spending-limits.mdx#rastreamento-de-uso).

Veja [Recuperar o uso de um limite](/pt/reference/tracer/retrieve-limit-usage).

***

## Passo 6: Mude, pause, remova

***

<Steps>
  <Step title="Suba ou baixe o teto">
    ```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` e `scopes` são editáveis, e os campos de janela de tempo e de período personalizado também. `limitType` e `currency` não são — uma requisição que envia qualquer um dos dois é recusada com `0380`, e um período ou uma moeda diferente significa um limite novo. Um corpo sem nada dentro é recusado com `0183`. Veja [Atualizar um limite](/pt/reference/tracer/update-limit).

    Mudar o teto não apaga a contagem em curso. Baixe-o abaixo do que o período atual já consumiu e a conta fica negada até o próximo período começar.
  </Step>

  <Step title="Pare de aplicá-lo">
    ```bash theme={null}
    curl -X POST http://localhost:4020/v1/limits/{limitId}/deactivate \
      -H "X-API-Key: your-secure-api-key"
    ```

    O limite passa para `INACTIVE` e deixa de ser conferido. Ele mantém a definição e o lugar no <GAuditTrail>rastro de auditoria</GAuditTrail>, e `POST /v1/limits/{limitId}/activate` o devolve ao caminho. Veja [Desativar um limite](/pt/reference/tracer/deactivate-limit).
  </Step>

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

    Devolve um limite `INACTIVE` para `DRAFT`. Veja [Devolver um limite para rascunho](/pt/reference/tracer/draft-limit).
  </Step>

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

    Responde `204`. Um limite que está `ACTIVE` precisa ser desativado antes — o Tracer recusa a exclusão com `0363`, que é o que impede um teto vigente de sumir por acidente. Veja [Excluir um limite](/pt/reference/tracer/delete-limit).
  </Step>
</Steps>

### Encontre os limites que você já tem

`GET /v1/limits` lista os limites e filtra pelos mesmos campos de escopo que você definiu no passo 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` e `sub_type` filtram; os resultados são paginados por cursor. Veja [Listar limites](/pt/reference/tracer/list-limits), e [Recuperar um limite](/pt/reference/tracer/retrieve-limit) para um por id.

***

## O que dá errado

***

<Warning>
  **O que costuma dar errado ao configurar um teto:**

  * **"O cliente estourou e nada o deteve."** Confira `status` primeiro — um limite em `DRAFT` ou `INACTIVE` não é conferido. Depois confira se a `currency` do limite casa com a da transação, e se o escopo nomeia o id que a transação de fato carregava.
  * **"O teto do segmento acabou no segundo dia."** Um limite com escopo de segmento é um orçamento para o segmento inteiro, não um por conta dentro dele. Um teto por conta significa um limite dirigido a cada conta.
  * **"O mês virou algumas horas antes."** As viradas de período são em UTC. O gasto depois das 21:00 em UTC-3 pertence ao dia UTC seguinte, e no último dia do mês, ao mês seguinte.
  * **"Aumentei o limite e a conta continua negada."** Aumentar o teto não apaga a contagem. Confirme que o novo `maxAmount` está acima do que o período já consumiu.
  * **"`GET /v1/limits/{id}/usage` informa mais do que o cliente gastou neste mês."** Esse endpoint totaliza os contadores registrados para o limite, entre períodos e escopos. Para o período atual, leia `limitUsageDetails` na resposta de validação.
</Warning>

### Códigos de erro

| Código | Status | O que mudar                                                                                                                                                                                       |
| ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0009` | 400    | Um campo falhou na validação — `detail` nomeia qual, por exemplo `scopes must have at least 1 item(s)`, `scope at index 0 must have at least one field set` ou `maxAmount must be greater than 0` |
| `0065` | 400    | O id no caminho não é um UUID                                                                                                                                                                     |
| `0183` | 400    | O corpo do `PATCH` não trouxe nenhum campo editável                                                                                                                                               |
| `0362` | 404    | Nenhum limite tem esse id                                                                                                                                                                         |
| `0363` | 422    | A transição não é permitida — excluir um limite `ACTIVE`, por exemplo                                                                                                                             |
| `0366` | 400    | `currency` tem três letras maiúsculas, mas não é um código ISO 4217                                                                                                                               |
| `0371` | 400    | `name` traz um caractere que o campo não aceita                                                                                                                                                   |
| `0380` | 422    | A requisição tentou mudar `limitType` ou `currency`                                                                                                                                               |
| `0442` | 409    | Outro limite vigente já ocupa esse nome                                                                                                                                                           |

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

***

## Referência rápida

***

| Passo                           | Método | Endpoint                         |
| ------------------------------- | ------ | -------------------------------- |
| Criar um limite                 | POST   | `/v1/limits`                     |
| Ativar                          | POST   | `/v1/limits/{id}/activate`       |
| Ler o consumo com a decisão     | POST   | `/v1/validations`                |
| Ler o total acumulado do limite | GET    | `/v1/limits/{id}/usage`          |
| Mudar o teto                    | PATCH  | `/v1/limits/{id}`                |
| Parar de aplicar                | POST   | `/v1/limits/{id}/deactivate`     |
| Devolver para rascunho          | POST   | `/v1/limits/{id}/draft`          |
| Remover                         | DELETE | `/v1/limits/{id}`                |
| Encontrar limites               | GET    | `/v1/limits` · `/v1/limits/{id}` |
