PINTI Docs

Policy Engine

How PINTI evaluates spend intents against your policies.

Mental Model

Every spend intent goes through an evaluation pipeline. Think of it as a series of gates — the first failure short-circuits the evaluation:

Policy exists?
  → Merchant not blocked?
    → Category not blocked?
      → Merchant in whitelist? (if set)
        → Category in whitelist? (if set)
          → Under single-transaction limit?
            → Under daily limit?
              → Under monthly limit?
                → Under velocity limits?
                  → Under approval threshold?
                    → ALLOW ✓

Evaluation Pipeline

#CheckDecisionReason
1Policy exists and is activeDENYNO_ACTIVE_POLICY
2Merchant not in blockedMerchantsDENYBLOCKED_MERCHANT
3Category not in blockedCategoriesDENYBLOCKED_CATEGORY
4Merchant in allowedMerchants (if set)DENYMERCHANT_NOT_ALLOWED
5Category in allowedCategories (if set)DENYCATEGORY_NOT_ALLOWED
6Amount ≤ maxSingleAmountDENYEXCEEDS_SINGLE_LIMIT
7(dailyTotal + amount) ≤ dailyLimitDENYEXCEEDS_DAILY_LIMIT
8(monthlyTotal + amount) ≤ monthlyLimitDENYEXCEEDS_MONTHLY_LIMIT
9Transactions/min ≤ maxTransactionsPerMinuteDENYVELOCITY_LIMIT_MINUTE
10Transactions/hour ≤ maxTransactionsPerHourDENYVELOCITY_LIMIT_HOUR
11Amount ≤ requireApprovalOverREQUIRE_APPROVALREQUIRES_APPROVAL
12All checks passedALLOWOK

Note

When the decision is REQUIRE_APPROVAL, the spend is paused until a human approves or rejects it. See Approvals & Callbacks for the full notification and callback flow.

Note

Daily and monthly totals only count ALLOW decisions. Denied or pending-approval requests don't count toward your limits.

Policy Fields

FieldTypeDescription
namestringHuman-readable policy name
unitstringCurrency unit (e.g. "USD"). Must match the intent.
maxSingleAmountnumber | nullMax allowed per single transaction (minor units). Null = no limit.
dailyLimitnumber | nullMax total spend per day (UTC). Null = no limit.
monthlyLimitnumber | nullMax total spend per month (UTC). Null = no limit.
requireApprovalOvernumber | nullAmounts above this trigger human approval. Null = never require.
maxTransactionsPerMinutenumber | nullMax transactions per minute. Null = no limit.
maxTransactionsPerHournumber | nullMax transactions per hour. Null = no limit.
allowedMerchantsstring[]Whitelist. Empty = allow all. Non-empty = only these merchants.
blockedMerchantsstring[]Blocklist. These merchants are always denied.
allowedCategoriesstring[]Whitelist. Empty = allow all. Non-empty = only these categories.
blockedCategoriesstring[]Blocklist. These categories are always denied.
isActivebooleanToggle policy on/off without deleting.

Policy Resolution

PINTI uses the first active policy in your workspace. If no active policy exists, all spend intents are denied with NO_ACTIVE_POLICY.

Tip

Only one policy can be active at a time per workspace. Toggle policies on/off from the Dashboard to switch between rule sets.

Best Practices

Start Simple

Begin with one policy with conservative limits. Increase limits as you build confidence in your agent's behavior.

Example Policy Sets

Basic daily limit

$50/day limit, no single-transaction cap
{
  "name": "Conservative",
  "dailyLimit": 5000,
  "unit": "USD"
}

OpenAI-only with approval threshold

Only OpenAI, approve over $50
{
  "name": "OpenAI Only",
  "allowedMerchants": ["openai.com"],
  "requireApprovalOver": 5000,
  "dailyLimit": 50000,
  "unit": "USD"
}

Blocked merchant list with velocity limits

Block bad merchants, max 10 tx/min
{
  "name": "Production Policy",
  "blockedMerchants": ["evil.com", "scam.io"],
  "maxSingleAmount": 20000,
  "dailyLimit": 100000,
  "monthlyLimit": 1000000,
  "maxTransactionsPerMinute": 10,
  "maxTransactionsPerHour": 100,
  "requireApprovalOver": 10000,
  "unit": "USD"
}

Note

All amount fields are in minor currency units (e.g. 5000 = $50.00 in cents).