Skip to main content

Documentation Index

Fetch the complete documentation index at: https://spendguard.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

SpendGuard policies are built from rules. Each rule has a rule_type that determines what it checks. You can combine any number of rules in a single policy. Decision precedence: If multiple rules fire, block wins over escalate, and escalate wins over allow.

1. max_amount

What it does: Blocks any action where the dollar amount exceeds a limit. Decision: block Parameters:
ParameterTypeDescription
limitnumberMaximum allowed amount
currencystringCurrency code (e.g., “USD”)
Example rule:
{
  "rule_id": "r1",
  "rule_type": "max_amount",
  "description": "Block transactions over $500",
  "parameters": {
    "limit": 500,
    "currency": "USD"
  }
}
Triggering example: A $750 refund would return:
{
  "decision": "block",
  "reason_code": "max_amount_exceeded",
  "message": "Amount $750.00 exceeds the policy limit of $500.00.",
  "violated_rule_id": "r1"
}

2. refund_age_limit

What it does: Blocks refunds on purchases older than a specified number of days. Only applies when action_type is refund. Decision: block Parameters:
ParameterTypeDescription
max_daysintegerMaximum days since purchase
Requires metadata: days_since_purchase (integer) must be included in the check request’s metadata field. If missing, the rule does not trigger. Example rule:
{
  "rule_id": "r2",
  "rule_type": "refund_age_limit",
  "description": "No refunds after 30 days",
  "parameters": {
    "max_days": 30
  }
}
Triggering example: A refund with metadata.days_since_purchase = 45 would return:
{
  "decision": "block",
  "reason_code": "refund_age_limit_exceeded",
  "message": "Refund requested for an order 45 days old. Policy limit is 30 days.",
  "violated_rule_id": "r2"
}

3. blocked_categories

What it does: Blocks actions in prohibited categories. Checks the metadata.category field and also scans merchant_or_vendor for matching substrings. Decision: block Parameters:
ParameterTypeDescription
categoriesarray of stringsCategory names to block
Example rule:
{
  "rule_id": "r3",
  "rule_type": "blocked_categories",
  "description": "Block gambling and luxury goods",
  "parameters": {
    "categories": ["gambling", "luxury_goods"]
  }
}
Triggering example: A check with metadata.category = "gambling" would return:
{
  "decision": "block",
  "reason_code": "blocked_category",
  "message": "Category 'gambling' is blocked by policy.",
  "violated_rule_id": "r3"
}

4. vendor_allowlist

What it does: Blocks payments to vendors not on the approved list. Only applies when action_type is spend. Checks the counterparty field against the allowed vendors list. Decision: block Parameters:
ParameterTypeDescription
vendorsarray of stringsApproved vendor/counterparty IDs
Example rule:
{
  "rule_id": "r4",
  "rule_type": "vendor_allowlist",
  "description": "Only approved vendors",
  "parameters": {
    "vendors": ["vendor_acme", "vendor_globex", "vendor_initech"]
  }
}
Triggering example: A spend check with counterparty = "vendor_unknown" would return:
{
  "decision": "block",
  "reason_code": "vendor_not_on_allowlist",
  "message": "Vendor 'vendor_unknown' is not on the approved vendor list.",
  "violated_rule_id": "r4"
}

5. blocked_payment_rails

What it does: Blocks specific payment methods. Checks the payment_method field (case-insensitive). Decision: block Parameters:
ParameterTypeDescription
railsarray of stringsPayment methods to block (e.g., “wire”, “crypto”, “cash”)
Example rule:
{
  "rule_id": "r5",
  "rule_type": "blocked_payment_rails",
  "description": "No wire or crypto payments",
  "parameters": {
    "rails": ["wire", "crypto"]
  }
}
Triggering example: A check with payment_method = "wire" would return:
{
  "decision": "block",
  "reason_code": "blocked_payment_rail",
  "message": "Payment method 'wire' is blocked by policy.",
  "violated_rule_id": "r5"
}
If payment_method is not included in the check request, this rule does not trigger. It only fires when a blocked method is explicitly provided.

6. discount_cap

What it does: Blocks discounts above a percentage cap. Only applies when action_type is discount. Decision: block Parameters:
ParameterTypeDescription
max_percentnumberMaximum allowed discount percentage
Requires metadata: discount_percent (number) must be included in the check request’s metadata field. If missing, the rule does not trigger. Example rule:
{
  "rule_id": "r6",
  "rule_type": "discount_cap",
  "description": "Max 20% discount",
  "parameters": {
    "max_percent": 20
  }
}
Triggering example: A discount with metadata.discount_percent = 35 would return:
{
  "decision": "block",
  "reason_code": "discount_cap_exceeded",
  "message": "Discount of 35% exceeds the policy cap of 20%.",
  "violated_rule_id": "r6"
}

7. geography_block

What it does: Blocks actions from certain countries. Checks metadata.country against the blocked list (case-insensitive). Decision: block Parameters:
ParameterTypeDescription
blocked_countriesarray of stringsISO 3166-1 alpha-2 country codes (e.g., “RU”, “KP”)
Requires metadata: country (string) must be included in the check request’s metadata field. Example rule:
{
  "rule_id": "r7",
  "rule_type": "geography_block",
  "description": "Block sanctioned countries",
  "parameters": {
    "blocked_countries": ["RU", "KP", "IR", "CU"]
  }
}
Triggering example: A check with metadata.country = "RU" would return:
{
  "decision": "block",
  "reason_code": "blocked_geography",
  "message": "Actions from country 'RU' are blocked by policy.",
  "violated_rule_id": "r7"
}

8. time_restriction

What it does: Blocks actions outside allowed days and/or hours (evaluated in UTC). Decision: block Parameters:
ParameterTypeDescription
allowed_daysarray of stringsAllowed day abbreviations: “mon”, “tue”, “wed”, “thu”, “fri”, “sat”, “sun”
allowed_hours_utcstringTime range in “HH:MM-HH:MM” format (e.g., “09:00-17:00”)
Example rule:
{
  "rule_id": "r8",
  "rule_type": "time_restriction",
  "description": "Business hours only",
  "parameters": {
    "allowed_days": ["mon", "tue", "wed", "thu", "fri"],
    "allowed_hours_utc": "09:00-17:00"
  }
}
Triggering example: A check at 3:00 AM UTC on a Tuesday would return:
{
  "decision": "block",
  "reason_code": "time_restriction_violated",
  "message": "Actions at 03:00 UTC are outside the allowed window of 09:00-17:00 UTC.",
  "violated_rule_id": "r8"
}

9. duplicate_guard

What it does: Blocks repeated identical actions within a configurable time window. An action is considered identical if it has the same agent_id, action_type, amount, and counterparty. Decision: block Parameters:
ParameterTypeDescription
window_minutesintegerHow many minutes to look back for duplicates (default: 5)
How it works:
  1. SpendGuard computes a SHA-256 fingerprint from agent_id|action_type|amount|counterparty
  2. If the same fingerprint exists within the window, the check returns block
  3. If not, the fingerprint is recorded and the check proceeds to other rules
Example rule:
{
  "rule_id": "r9",
  "rule_type": "duplicate_guard",
  "description": "Block duplicate actions within 10 minutes",
  "parameters": {
    "window_minutes": 10
  }
}
Triggering example: Submitting the same $50 refund to customer_123 twice within 10 minutes:
{
  "decision": "block",
  "reason_code": "duplicate_action_detected",
  "message": "This action was already submitted recently.",
  "violated_rule_id": null
}
The duplicate guard runs before all other rules. If it triggers, no other rules are evaluated.

10. escalate_if

What it does: Escalates (does not block) actions above a dollar threshold for specific action types. Use this for “human approval required above $X” scenarios. Decision: escalate Parameters:
ParameterTypeDescription
amount_abovenumberDollar threshold for escalation
action_typesarray of stringsWhich action types this applies to (e.g., [“refund”, “credit”])
Example rule:
{
  "rule_id": "r10",
  "rule_type": "escalate_if",
  "description": "Escalate refunds over $200",
  "parameters": {
    "amount_above": 200,
    "action_types": ["refund"]
  }
}
Triggering example: A $300 refund would return:
{
  "decision": "escalate",
  "reason_code": "escalation_threshold_exceeded",
  "message": "Refund of $300.00 exceeds the escalation threshold of $200.00.",
  "violated_rule_id": "r10"
}
If a max_amount rule and an escalate_if rule both fire on the same check, the block from max_amount wins. Block always takes precedence over escalate.

Quick Reference Table

Rule TypeDecisionKey ParametersApplies To
max_amountblocklimit, currencyAll action types
refund_age_limitblockmax_daysrefund only
blocked_categoriesblockcategoriesAll (checks metadata + merchant)
vendor_allowlistblockvendorsspend only
blocked_payment_railsblockrailsAll (checks payment_method)
discount_capblockmax_percentdiscount only
geography_blockblockblocked_countriesAll (checks metadata.country)
time_restrictionblockallowed_days, allowed_hours_utcAll action types
duplicate_guardblockwindow_minutesAll (runs first)
escalate_ifescalateamount_above, action_typesSpecified types