Skip to main content
A product or risk decision has landed as a sentence: “no more than R$ 20,000 per account per month.” This guide turns that sentence into a live cap, and shows where to read how much of it a customer has left. What changes in your operation: the ceiling stops being a constant compiled into a service. It becomes a stored definition you create, activate, raise, and stop — and every decision that touches it reports what it consumed.
Who is this guide for? Product and risk teams setting the ceiling, and developers wiring POST /v1/validations into the payment path. Steps 1 and 2 are decisions to make before any call; steps 3 to 6 are the calls.

Before you start


  • Tracer running and reachable, with an API key — see Getting started
  • The id of the account, portfolio, or segment the cap applies to
  • The currency of the transactions you want capped
  • Familiarity with limit types, time windows, and custom periods — see Spending limits
All calls below send the API key as X-API-Key and run against http://localhost:4020.

Step 1: Decide what the cap is addressed to


A limit carries a list of scope objects, and each object names what the limit applies to. These fields are available inside one object: Fields inside one object combine with AND. A field you leave out is a wildcard. Across objects the list combines with OR, so a limit with two objects applies when either one matches. The choice that decides the answer to “R$ 20,000 per account” is which id you name:
The cap is addressed to that account. It counts that account’s spending and no one else’s. For a per-account ceiling across a book of customers, each account gets its own limit.
A limit also carries a currency, and Tracer checks a limit against a transaction only when the two match. A limit created in BRL is not checked against a USD transaction, so a book that settles in two currencies needs a limit for each.
A limit must carry at least one scope object, and each object must set at least one field. An empty list, or an empty object, is rejected — see What goes wrong.

Step 2: Choose the period


limitType decides both the size of the ceiling’s window and when a new count starts. Tracer offers five: “per month” is MONTHLY.
The boundary is UTC, not local time. A São Paulo customer spending at 21:30 on 31 July is at 00:30 UTC on 1 August, so that amount lands in the August count, not July’s. When a cap is agreed in local terms, expect the last hours of the local month to belong to the next one.
CUSTOM takes customStartDate and customEndDate and is the shape for a campaign or a promotion. Those two fields belong to CUSTOM and are rejected on the other four types. To restrict a cap to certain hours of the day instead, see time windows.

Step 3: Create the limit


POST /v1/limits stores the definition. It is created in DRAFT, which means it is stored but not yet checked.
A successful call answers 201. The body is the stored limit; two fields matter now:
Names are unique across limits, and the character set is narrow. name accepts ASCII letters and digits, spaces, and -, _, ., (, ). An accent or a dash typed as an em dash is rejected with 0371. A name another live limit already holds is rejected with 0442; deleting a limit frees its name again.
For the full payload and every optional field, see Create a limit.

Step 4: Activate it


A DRAFT limit is not checked. Activation is what puts it in the path:
The response carries the limit with status set to ACTIVE. From here, every POST /v1/validations whose transaction matches the scope and the currency is measured against it.
Activating mid-month does not import the month’s history. Tracer counts a transaction against a limit at the moment it decides on it, so spending that happened while the limit was DRAFT is not in the count. A cap activated on the 20th governs what happens from the 20th onward.
See Activate a limit.

Step 5: Read how much is left


Every POST /v1/validations response carries limitUsageDetails, with one entry per limit Tracer checked:
In the entry above, a R$ 1,500 purchase took an 18,500 month to exactly 20,000 — the cap is now spent, and the next transaction on that account is denied until August. When a limit is exceeded, the decision is DENY and reason is limit_exceeded; the amount that would have crossed the ceiling is not added to the count. A limit produces a denial, not a flag for review. To go from such a denial back to the limit that caused it, see Reviewing a denied transaction.

The other reading

GET /v1/limits/{limitId}/usage answers with a total for the limit rather than for one period: it adds up the usage counters recorded against it, across the periods and scopes it has accumulated. Use it to review how much a limit has absorbed overall — not to answer how much a customer has left this month. A counter is deleted 90 days after its period ends, so on a long-running limit this total covers only the periods still retained, not the limit’s full lifetime. See Usage tracking. See Retrieve a limit usage snapshot.

Step 6: Change it, pause it, remove it


1

Raise or lower the ceiling

name, description, maxAmount, and scopes are editable, and so are the time-window and custom-period fields. limitType and currency are not — a request that sends either is rejected with 0380, and a different period or currency means a new limit. A body with nothing in it is rejected with 0183. See Update a limit.Changing the ceiling does not clear the running count. Lower it below what the current period already consumed and the account is denied until the next period starts.
2

Stop enforcing it

The limit moves to INACTIVE and stops being checked. It keeps its definition and its place in the , and POST /v1/limits/{limitId}/activate puts it back in the path. See Deactivate a limit.
3

Take it back to draft

Moves an INACTIVE limit back to DRAFT. See Return a limit to draft.
4

Remove it

Answers 204. A limit that is currently ACTIVE has to be deactivated first — Tracer rejects the deletion with 0363, which is what keeps a live ceiling from disappearing by accident. See Delete a limit.

Find the limits you already have

GET /v1/limits lists them, and filters by the same scope fields you set in Step 1:
name, status, limit_type, account_id, segment_id, portfolio_id, merchant_id, transaction_type, and sub_type all filter; results are cursor-paginated. See List limits, and Retrieve a limit for one by id.

What goes wrong


What usually goes wrong when a cap is set up:
  • “The customer overspent and nothing stopped them.” Check status first — a limit in DRAFT or INACTIVE is not checked. Then check that the limit’s currency matches the transaction’s, and that the scope names the id the transaction actually carried.
  • “The segment cap ran out on day two.” A segment-scoped limit is one budget for the whole segment, not one per account in it. A per-account ceiling means a limit addressed to each account.
  • “The month rolled over a few hours early.” Period boundaries are UTC. Spending after 21:00 in UTC-3 belongs to the next UTC day, and on the last day of the month, to the next month.
  • “I raised the limit and the account is still denied.” Raising the ceiling does not clear the count. Confirm the new maxAmount is above what the period already consumed.
  • GET /v1/limits/{id}/usage reports more than the customer spent this month.” That endpoint totals the counters recorded for the limit, across periods and scopes. For the current period, read limitUsageDetails on the validation response.

Error codes

The complete list is in the Tracer error list.

Quick reference