Skip to main content

Risk Policies

Automatically detect suspicious spending patterns and take action—from alerting to freezing cards to suspending agents.

How it works

StepWhat happens
ConfigureSet detection rules at org, agent, or card level
TransactRisk engine evaluates each transaction in real-time
DetectAnomalies trigger configured actions
RespondAlert, freeze card, or suspend agent automatically

Presets

Start with a preset and customize from there:
PresetDescriptionUse case
permissiveMinimal detection, alert-onlyTrusted agents, low-risk operations
moderateBalanced detection with alertsGood starting point
strictAggressive detection, auto-freeze cardsHigh-value transactions
paranoidMaximum protection, auto-suspend agentsUntrusted or new agents
curl -X POST https://api.ledger.so/v1/settings/risk/preset \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"preset": "moderate"}'

Detection rules

Duplicate detection

Catches agents accidentally repeating the same purchase.
{
  "duplicateDetection": {
    "enabled": true,
    "windowMinutes": 5,
    "action": "freeze_card"
  }
}
Triggers when same merchant + same amount occurs within the time window.

Velocity limits

Prevents runaway loops making too many transactions.
{
  "velocityLimit": {
    "enabled": true,
    "maxPerHour": 20,
    "maxPerDay": 100,
    "action": "alert"
  }
}

Spend spike detection

Catches sudden spending surges compared to historical patterns.
{
  "spendSpike": {
    "enabled": true,
    "multiplier": 3.0,
    "windowMinutes": 60,
    "baselineDays": 7,
    "action": "freeze_card"
  }
}
Triggers when current spending rate exceeds multiplier times the average over baselineDays.

Unattested spend

Responds when a transaction occurs without prior credential attestation.
{
  "unattestedSpend": {
    "enabled": true,
    "action": "alert"
  }
}

Intent mismatch

Responds when a transaction doesn’t match the declared spending intent.
{
  "intentMismatch": {
    "enabled": true,
    "action": "alert"
  }
}

Cooldown violation

Detects transactions that occur too quickly after the previous one.
{
  "cooldownViolation": {
    "enabled": true,
    "action": "alert"
  }
}

Merchant drift

Detects when a multi-use card is used at an unexpected merchant.
{
  "merchantDrift": {
    "enabled": true,
    "action": "freeze_card"
  }
}

Actions

ActionBehavior
alertEmit webhook, allow transaction to proceed
freeze_cardFreeze the card after transaction completes
suspend_agentSuspend the agent and freeze all its cards

Layered inheritance

Risk policies cascade: Org → Agent → Card
Organization (baseline)
└── Agent (can override any org setting)
    └── Card (can enable/disable specific rules)

Organization level

Set defaults for all agents in your organization:
curl -X PATCH https://api.ledger.so/v1/settings/risk \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "duplicateDetection": {
      "enabled": true,
      "windowMinutes": 5,
      "action": "alert"
    },
    "velocityLimit": {
      "enabled": true,
      "maxPerHour": 50,
      "action": "alert"
    }
  }'

Agent level

Override org defaults for a specific agent:
curl -X PATCH https://api.ledger.so/v1/agents/$AGENT_ID \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "riskPolicy": {
      "preset": "strict",
      "velocityLimit": {
        "enabled": true,
        "maxPerHour": 10,
        "action": "freeze_card"
      }
    }
  }'

Card level

Enable or disable specific rules for a card:
curl -X POST https://api.ledger.so/v1/agents/$AGENT_ID/cards \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "purpose": "Large one-time purchase",
    "maxAmount": 100000,
    "riskPolicy": {
      "velocityLimit": { "enabled": false }
    }
  }'

Dry-run mode

Test your risk policies without taking action. Anomalies are detected and webhooks are emitted, but cards aren’t frozen and agents aren’t suspended.
curl -X POST https://api.ledger.so/v1/settings/risk/dry-run \
  -H "Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
Use dry-run to:
  • Tune thresholds before going live
  • Monitor what would trigger without disrupting operations
  • Test new rules on production traffic safely

Webhook events

Risk anomalies emit webhook events:
EventDescription
anomaly.duplicateDuplicate transaction detected
anomaly.velocityVelocity limit exceeded
anomaly.spend_spikeSpending spike detected
anomaly.unattestedUnattested spend detected
anomaly.intent_mismatchIntent mismatch detected
anomaly.cooldownCooldown violation detected
anomaly.merchant_driftMerchant drift detected
card.auto_frozenCard automatically frozen by risk engine
agent.auto_suspendedAgent automatically suspended by risk engine
Example webhook payload:
{
  "type": "anomaly.velocity",
  "data": {
    "cardId": "card_abc123",
    "agentId": "agent_xyz789",
    "transactionId": "txn_def456",
    "action": "freeze_card",
    "dryRun": false,
    "details": {
      "count": 25,
      "limit": 20,
      "window": "hour"
    }
  }
}

Notes

  • Risk evaluation runs synchronously on each incoming transaction webhook
  • Actions are taken after the transaction completes (post-authorization)
  • Dry-run mode is per-organization and applies to all detection rules
  • Card-level overrides can only enable/disable rules, not change thresholds