Skip to main content

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.

Spending limits are how product and risk teams cap exposure per customer, per segment, or per portfolio without writing code. Common use cases: a daily ceiling on card spending for retail customers, a monthly cap on a specific MCC, a campaign-window limit for a marketing promotion. What changes in your operation: spending caps stop being constants hardcoded in config files or scattered across services. They become versioned data with a clear lifecycle (DRAFT → ACTIVE → INACTIVE), they reset on the period boundary automatically, and they’re audit-trailed every time a transaction would have pushed past one. Trade-off to be honest about: counters need to stay consistent across replicas and races. Tracer handles that transactionally — if a transaction is denied or sent to REVIEW, the counter rolls back. You give up “local clever logic in each service” and gain a single, consistent number.
Who is this guide for? Product managers configuring caps, risk teams reviewing exposure, compliance auditing what was denied, and developers integrating the validation call. The Limit types section assumes no API knowledge; the lifecycle and PATCH sections assume basic REST.
Spending limits in Tracer let you control transaction amounts by scope (account, portfolio, segment) and period (daily, weekly, monthly, custom, or per-transaction). Limits are evaluated in real-time alongside rules, in the same POST /v1/validations call.

Why use spending limits


  • Customer protection: Detect overspending and return DENY decisions for unauthorized large transactions
  • Risk management: Monitor exposure per account, segment, or portfolio
  • Flexible scoping: Apply limits at different granularity levels
  • Real-time tracking: Monitor usage and remaining amounts instantly
  • Automatic resets: Daily, weekly, monthly, and custom limits reset automatically
  • Time windows: Restrict limit enforcement to specific hours of the day
  • Custom periods: Define date-bound limits for campaigns, promotions, or compliance requirements
By the end of this guide, you will:
  • Understand limit types, time windows, and scoping options
  • Create and configure spending limits with period-based controls
  • Monitor limit usage in real-time
  • Manage the limit lifecycle

Core concepts


Understand the building blocks of spending limits.

Limit types

Tracer supports five types of spending limits:
TypeDescriptionReset behavior
DAILYMaximum amount per dayResets at midnight UTC
WEEKLYMaximum amount per weekResets every Monday at 00:00 UTC
MONTHLYMaximum amount per monthResets on 1st of month, midnight UTC
CUSTOMMaximum amount within a user-defined date rangeResets at customEndDate + 1 day at midnight UTC
PER_TRANSACTIONMaximum amount per single transactionNo tracking; each transaction evaluated independently

Time windows

Time windows restrict when a limit is enforced during the day. When a transaction occurs outside the configured time window, the limit is skipped (not enforced) and the transaction is allowed to proceed without counting against that limit.
  • Format: HH:MM (24-hour, UTC)
  • Both fields required: If activeTimeStart is set, activeTimeEnd must also be set (and vice versa)
  • Half-open interval: Start is inclusive, end is exclusive [start, end)
  • Overnight windows supported: Setting activeTimeStart: "20:00" and activeTimeEnd: "06:00" creates a window from 8 PM to 6 AM UTC
Time windows can be applied to any limit type (DAILY, WEEKLY, MONTHLY, CUSTOM, or PER_TRANSACTION). If no time window is configured, the limit is active 24/7.
Example: PIX compliance A financial institution needs to enforce lower PIX transfer limits during nighttime hours (as recommended by BACEN):
  • limitType: DAILY
  • maxAmount: "1000.00"
  • activeTimeStart: "20:00"
  • activeTimeEnd: "06:00"
  • Scope: PIX transactions
Transactions between 20:00 and 06:00 UTC are checked against the R$ 1,000 limit. Transactions outside this window are not affected by this limit.

Custom periods

Custom periods define a date range during which a limit is active. This is useful for campaigns, promotions, seasonal events, or compliance requirements with specific date boundaries.
  • Required fields: customStartDate and customEndDate (only for CUSTOM type)
  • Half-open interval: Start is inclusive, end is exclusive [start, end)
  • Maximum duration: 5 years
  • Cannot be in the past: The customEndDate must not be entirely before the current date
The customStartDate and customEndDate fields are required for CUSTOM limits and forbidden for other limit types.
Example: Black Friday campaign A retailer wants to set a special spending limit for the Black Friday period:
  • limitType: CUSTOM
  • maxAmount: "100000.00"
  • customStartDate: "2026-11-25T00:00:00Z"
  • customEndDate: "2026-11-30T00:00:00Z"
  • Scope: CARD transactions in the retail segment
Usage accumulates across the entire 5-day period. After November 30, the limit is no longer enforced.

Combining time windows and custom periods

Time windows and custom periods can be used together on CUSTOM limits. When combined, a transaction must be within both the custom period and the time window to be evaluated against the limit. For example, a CUSTOM limit with customStartDate Nov 25 to customEndDate Nov 30 and a time window of 09:00 to 18:00 would only enforce the limit during business hours within the Black Friday period.

Scopes

Scopes define which transactions a limit applies to. Unlike rules, every limit must have at least one scope object — limits cannot be global. Within a single scope object, the supported fields are:
  • segmentId - Apply to transactions from a specific segment
  • portfolioId - Apply to transactions from a specific portfolio
  • accountId - Apply to transactions from a specific account
  • merchantId - Apply to transactions to a specific merchant
  • transactionType - Apply to specific transaction types (CARD, WIRE, PIX, CRYPTO)
  • subType - Apply to a specific transaction subtype (e.g., debit, credit)
Matching semantics:
  • Within one scope object: fields combine with AND. A field that is not specified is treated as a wildcard (matches any value). At least one field must be set — empty scope objects ({}) are rejected with TRC-0125.
  • Across multiple scope objects on the same limit: they combine with OR. The limit applies if any scope object matches the transaction.
No hierarchy between limits. When a transaction matches multiple limits (for example, both an account-level and a segment-level limit), Tracer checks all applicable limits independently in a single transaction. The transaction is denied as soon as any one of them is exceeded.

Usage tracking

For DAILY, WEEKLY, MONTHLY, and CUSTOM limits, Tracer tracks:
  • Current usage - Total amount consumed in the current period (as a decimal value)
  • Utilization percent - Percentage of limit used
  • Reset time - When the limit will reset to zero
Usage counters are retained for 90 days after expiration for auditing purposes, then automatically cleaned up by a background worker.

How limits work


Tracer evaluates limits during every validation request.

Limit check flow

When a transaction is validated, Tracer checks all applicable limits:
  1. Find limits - Query all active limits matching the transaction scope
  2. Check time window - If the limit has a time window configured, verify the current server time falls within activeTimeStart/activeTimeEnd. If outside, the limit is skipped (the client-supplied transactionTimestamp is not used here)
  3. Check custom period - If the limit is CUSTOM, verify the current server time falls within customStartDate/customEndDate. If outside, the limit is skipped (again, transactionTimestamp is not used)
  4. Calculate projected usage - Add transaction amount to current usage
  5. Compare threshold - Check if projected usage exceeds limit amount
  6. Return result - If any applicable limit is exceeded — or any DENY rule matches — Tracer returns a DENY decision (your system should then block the transaction)
Limit checks and counter increments are transactional. If a transaction is denied (by limits or rules) or flagged for review, all counter increments are rolled back atomically. This prevents limit leakage from partial operations.
When a limit is skipped during evaluation, limitUsageDetails[i] includes skipped: true and a skipReason field with one of two values:
  • "outside_time_window" — current server time is outside the limit’s activeTimeStart/activeTimeEnd window
  • "outside_custom_period" — current server time is outside the limit’s customStartDate/customEndDate range
Skipped limits are reported for transparency but do not participate in the DENY decision, and their counters are not incremented. The window check uses server time, not the client-supplied transactionTimestamp, to prevent timestamp-manipulation attacks.
Why server time instead of transactionTimestamp. The client can set transactionTimestamp to whatever they want — including a value crafted to fall inside an active window when the real transaction would fall outside it. If Tracer trusted the client clock for time-window enforcement, anyone with access to the payload could bypass off-hours limits. Pinning the window check to Tracer’s own clock removes that attack surface. The downside is that small clock drift between Tracer pods can cause edge-case skips around the window boundary; in practice, Tracer’s NTP-synced clocks keep this in single-digit milliseconds.

Example scenario

A corporate segment has a daily limit of R$ 50,000 ("50000.00") for CARD transactions. If current usage is R45,000andanewtransactionofR 45,000 and a new transaction of R 8,000 arrives:
  • Projected usage: R45,000+R 45,000 + R 8,000 = R$ 53,000
  • Limit: R$ 50,000
  • Result: Tracer returns DENY decision (your system should block the transaction)

Create a limit


Create limits using POST /v1/limits. Limits are created in DRAFT status by default. A limit requires:
  • name: A descriptive name (e.g., “Daily Corporate Card Limit”)
  • limitType: DAILY, WEEKLY, MONTHLY, CUSTOM, or PER_TRANSACTION
  • maxAmount: Maximum amount as a decimal value (e.g., "50000.00")
  • currency: ISO 4217 currency code (e.g., BRL, USD)
  • scopes: At least one scope to define which transactions it applies to
Optional fields:
  • activeTimeStart: Start of the daily time window in HH:MM format (e.g., "09:00")
  • activeTimeEnd: End of the daily time window in HH:MM format (e.g., "17:00")
  • customStartDate: Start date for CUSTOM limits (ISO 8601 timestamp, required for CUSTOM)
  • customEndDate: End date for CUSTOM limits (ISO 8601 timestamp, required for CUSTOM)
Limit names must be globally unique (across all limits). Name comparison is case-insensitive and ignores extra whitespace. Attempting to create or update a limit with a duplicate name returns a 409 Conflict response.
For complete payload structure and field details, see the API reference.

List and query limits


Query limits for management and auditing using GET /v1/limits.

Query parameters

ParameterTypeDescription
namestringFilter by name (case-insensitive partial match)
statusstringFilter by status (DRAFT, ACTIVE, INACTIVE)
limit_typestringFilter by limit type (DAILY, WEEKLY, MONTHLY, CUSTOM, PER_TRANSACTION)
account_idstringFilter by scope: account ID
segment_idstringFilter by scope: segment ID
portfolio_idstringFilter by scope: portfolio ID
merchant_idstringFilter by scope: merchant ID
transaction_typestringFilter by scope: transaction type (CARD, WIRE, PIX, CRYPTO)
sub_typestringFilter by scope: subtype (e.g., debit, credit)
limitintegerItems per page (default: 10, max: 100)
cursorstringPagination cursor
sort_bystringSort field: created_at, updated_at, name, max_amount
sort_orderstringSort direction: ASC, DESC (default: DESC)

Get a specific limit

Use GET /v1/limits/{id} to retrieve the full limit definition including scopes and current status.

Query limit usage


Monitor limit consumption using GET /v1/limits/{id}/usage. The response includes:
  • currentUsage: Amount consumed in current period
  • utilizationPercent: Percentage of limit used
  • nearLimit: True when utilizationPercent > 80strictly greater than 80%, not equal (for proactive management)
  • resetAt: When the limit resets (DAILY, WEEKLY, MONTHLY, and CUSTOM only)
The nearLimit flag turns true when utilizationPercent > 80 — strictly greater than 80%, not equal — so usage at exactly 80% does not yet trip the flag.

Update a limit


Update limits using PATCH /v1/limits/{id}. The limitType and currency fields are immutable and cannot be changed after creation.
Changing the limit amount does not reset current usage. If you reduce a limit below current usage, subsequent transactions will be denied until the period resets.

Limit lifecycle


Limits follow the same lifecycle as rules:

States

StateDescription
DRAFTLimit created but not active; can be modified freely
ACTIVELimit is checked during validations
INACTIVELimit is not checked; preserved for ; can be reactivated
DELETEDPermanently removed; does not appear in listings

Transitions

OperationFromToDescription
Create-DRAFTLimits are created in DRAFT status by default
ActivateDRAFT, INACTIVEACTIVEStart checking this limit
DeactivateACTIVEINACTIVEStop checking this limit
DraftINACTIVEDRAFTReturn to draft for editing
DeleteDRAFT, INACTIVEDELETEDPermanently remove (cannot delete ACTIVE limits)

Best practices


Recommendations for effective limit management.

Naming

  • Be descriptive - Include the scope and type in the name
  • Use consistent patterns - e.g., “Daily Limit”
Less clearMore clear
Limit 1Daily Corporate Card Limit
VIP limitMonthly VIP PIX Limit
BF promoCustom Black Friday Card Limit

Scope design

  • Start broad, refine as needed - Begin with segment-level limits, add account-level for exceptions
  • Avoid overlapping scopes - Multiple limits on the same scope can cause confusion
  • Use transaction types - Different payment methods may need different limits

Time window design

  • Use for regulatory compliance - BACEN nighttime PIX limits are a common use case
  • Consider timezone impact - Time windows use UTC; account for your users’ local timezone offset
  • Combine with custom periods - Use time windows inside custom periods for precise campaign controls

Monitoring

  • Watch nearLimit flags - Proactively contact customers nearing limits
  • Review denied transactions - High denial rates may indicate limits are too restrictive
  • Adjust seasonally - Consider temporary limit increases during high-spending periods or use CUSTOM limits for specific date ranges
Common pitfalls when working with limits:
  • “My customer is reporting overspend — they should have hit the limit.” Check whether the limit is ACTIVE. A limit in DRAFT or INACTIVE state is not evaluated. Also confirm the limit’s scope actually matches the transaction (segment, transaction type, etc.).
  • “My PATCH lowered the limit but transactions are still being denied even after the period reset.” Lowering the limit doesn’t reset the counter. If current usage is already above the new ceiling, subsequent transactions will be denied until the next resetAt boundary.
  • “I tried to delete an ACTIVE limit and got a 400.” ACTIVE limits cannot be deleted — POST /v1/limits/{id}/deactivate first, then DELETE /v1/limits/{id}. This is intentional: it prevents accidentally removing a live enforcement.
  • “My nearLimit flag isn’t firing at 80% even though usage is exactly there.” The flag uses strict greater-than (utilizationPercent > 80), so usage at exactly 80% does not trip it.

Quick reference


Key endpoints and configuration options.

Endpoints

OperationMethodEndpoint
Create limitPOST/v1/limits
List limitsGET/v1/limits
Get limitGET/v1/limits/{id}
Update limitPATCH/v1/limits/{id}
Activate limitPOST/v1/limits/{id}/activate
Deactivate limitPOST/v1/limits/{id}/deactivate
Draft limitPOST/v1/limits/{id}/draft
Delete limitDELETE/v1/limits/{id}
Get usageGET/v1/limits/{id}/usage
For limit type definitions (DAILY, WEEKLY, MONTHLY, CUSTOM, PER_TRANSACTION), the optional time-window and custom-period fields, and the full scope-field list, see Limit types earlier in this guide and the API reference for schema-level details.