ArmorPay Observability

How AP, Finance, and Payroll agent plan captures, policy decisions, and tool results appear in ArmorIQ Observability.

ArmorPay agents run in SDK mode - they call the ArmorIQ backend directly through @armoriq/sdk or armoriq-sdk rather than sitting behind the MCP proxy (see Concepts and Getting Started). That SDK client is a standard observability producer, so ArmorPay activity follows the same path documented in the observability overview: each session becomes one OpenTelemetry trace, and policy checks and tool calls become spans.

What a trace looks like

Session (agent ID: "ap-agent")
└── Trace (armoriq.agent.run)
    ├── armoriq.intent.plan
    ├── armoriq.policy.evaluate
    │   ├── armoriq.policy.decision: allow | hold | deny
    │   ├── armoriq.policy.enforcement_action
    │   └── armoriq.policy.rule_id, armoriq.policy.reason_code
    ├── armoriq.approval.wait / armoriq.delegation.wait (when held)
    │   └── armoriq.delegation.id
    └── armoriq.tool (tool call)
        ├── armoriq.tool.name: create_invoice, record_payment, ...
        └── error.type (on failure)

The policy span's armoriq.policy.enforcement_action is the same value your ArmorPay policy resolved (see Concepts) - a threshold breach that resulted in hold shows up as armoriq.policy.decision: hold with a delegation span whose armoriq.delegation.id you can follow to the plan view.

ArmorIQ labels the telemetry with the product of the API key that the agent uses. The SDK has no separate armorpay producer identity.

Holds and delegation

When invokeWithPolicy opens a delegation (an amount, velocity, or recipient rule resolved to hold), the SDK records the hold on the policy span and adds a delegation span until a decision is made. Follow the armoriq.delegation.id in the span attributes to the plan detail view to see who approved or rejected it. See Getting Started for the client-side polling options (waitForApproval, holdPollIntervalMs, holdPollAttempts).

Freshness

Same as every SDK producer: the SDK sends spans in batches and sends the last ones when the session closes, and the dashboard polls every 30 seconds. See Freshness and retention for the full picture.

Enabling or disabling

Observability is on by default for any SDK client configured with an API key. To turn it off for an ArmorPay integration, pass the observability option through when constructing the client:

const client = new ArmorIQClient({
  apiKey: process.env.ARMORIQ_API_KEY!,
  userId: 'ap-service',
  agentId: 'ap-agent',
  observability: { enabled: false },
});

In Python, use SessionOptions(observability_enabled=False) for one session. Disabling telemetry never changes an enforcement decision - it only stops the trace from being recorded.

Privacy boundary

ArmorPay tool inputs and outputs can include vendor names, invoice amounts, and (for Payroll) employee identifiers. By default ArmorIQ stores metadata only, and it never stores tool inputs and outputs unless your organization chooses Enhanced or Debug capture and allows content. It always removes secrets, card numbers, and similar identifiers, but pattern-based redaction cannot catch everything - see What data is captured and Sensitive content. Avoid passing raw bank account numbers or full SSNs as tool parameters where you can use a reference ID instead, and restrict dashboard access to the org members who need it.

Next steps

On this page