ArmorPay Concepts
How ArmorPay bundle templates compile to a standard ArmorIQ policy document, and how amount, velocity, recipient, and transaction-type rules resolve at enforcement time.
ArmorPay is a specialized editor and template layer over ArmorIQ's normal policy engine, not a separate enforcement system. Everything you configure in the Policy Studio - member roles, thresholds, velocity caps, recipient rules - compiles down to one document type: kind: Policy, apiVersion: armor.io/v1.
ArmorPay does not use a distinct FinancialPolicy kind on the backend. The Policy Studio's guided sections are a friendlier editor for the same Policy document every ArmorIQ product targets an agent or MCP server with.
Shape of a compiled policy
apiVersion: armor.io/v1
kind: Policy
metadata:
name: standard-ap-controls
orgId: "<your-org-id>"
targetType: agent
targetId: "<ap-agent-id>"
spec:
priority: 100
status: active
defaultEnforcementAction: allow_log
memberRules:
"*":
allowedTools: [create_invoice, record_payment, list_customers]
enforcementAction: allow_log
amountThreshold:
maxPerTransaction: 10000
requireApprovalAbove: 5000
currency: USD
velocityLimit:
maxTransactionsPerHour: 200
maxCumulativePerDay: 50000
currency: USD
recipientValidation:
approvedVendors: []
blockPersonalAccounts: true
blockNewRecipients: false
transactionTypeControl:
allowedTypes: [invoice, payment]
blockedTypes: [wire_transfer]
readOnlyCategories: [balance]memberRules is keyed by member email for per-person rules, or "*" for a rule that applies to everyone the policy targets. Assigning a member to a role (Finance, AP, Payroll, Accountant, Finance Manager, CFO) in the Member Roles section is what creates a per-email entry instead of relying on the wildcard.
Domain-specific fields
| Field | Lives under | What it controls |
|---|---|---|
allowedTools | memberRules.<key> | Which tools this member/role can call at all |
toolEnforcement | memberRules.<key> | Per-tool override of the enforcement action (see resolution order below) |
amountThreshold | memberRules.<key> | maxPerTransaction, requireApprovalAbove, currency |
velocityLimit | memberRules.<key> | maxTransactionsPerHour, maxCumulativePerDay, currency |
recipientValidation | memberRules.<key> | approvedVendors, blockPersonalAccounts, blockNewRecipients |
transactionTypeControl | memberRules.<key> | allowedTypes, blockedTypes, readOnlyCategories |
multiPartyApproval | memberRules.<key> | requiredApprovers, approverRoles, channels for the approval workflow on held actions |
These map directly to the Policy Studio's Amount Threshold, Velocity Limit, Recipient Validation, and Transaction Types sections - the form is a view over these YAML fields, not a separate model.
Enforcement resolution order
For every tool call, ArmorIQ resolves the enforcement action in this order, and the first match wins:
toolEnforcement[toolName]on the matched member rulerule.enforcementActionon the matched member rulepolicy.spec.defaultEnforcementActionblock(fail-closed default when nothing else matches)
amountThreshold and velocityLimit don't set the enforcement action directly - they're inputs a policy author uses to decide what action to attach (for example, "hold anything over $5,000" means setting requireApprovalAbove: 5000 and enforcementAction: hold together).
Enforcement actions
| Action | Effect |
|---|---|
allow | Call proceeds, no log emphasis |
allow_log | Call proceeds, logged for audit |
hold | Call is paused pending a delegation/approval decision |
block | Call is refused |
deny | Call is refused (equivalent outcome to block at the SDK boundary) |
alert | Call proceeds, and an alert is raised |
quarantine | Call's output is isolated pending review rather than returned directly |
From bundle template to active policy
Applying a bundle template from the Dashboard does three things:
- Deactivates any existing active policy on that agent (a clean slate - ArmorPay does not layer partial bundles).
- Imports the bundle's YAML via upsert-by-name.
- Activates the resulting policy immediately - the next SDK call from that agent is evaluated against it.
Customizing a bundle in the Policy Studio edits the same document before deploy; nothing about the compiled YAML changes shape based on whether it started from a template or a blank policy.
How this reaches the agent at runtime
The policy above is only enforced once the agent actually calls through the SDK. See Getting Started for wiring an AP, Finance, or Payroll agent's invokeWithPolicy() call, and Observability for where the resulting decisions show up.