Enterprise

Per-key policy constraints

On top of scopes, every agent key can carry a JSON policy object that constrains what the key is allowed to do — independently of the user's IPS.

The policy shape

KeyPolicy
interface KeyPolicy {
  /** Cumulative cap on amountUsd across all propose calls per UTC day. */
  maxAmountUsdPerDay?: number;

  /** Ticker allowlist. If set, any other symbol returns
   *  key_policy_asset_not_allowed. */
  allowedAssets?: string[];

  /** Asset-class allowlist. If set, the other class is blocked. */
  allowedAssetTypes?: ('crypto' | 'tradfi')[];

  /** Local-time window. start/end in hours (0–23, half-open).
   *  Wrap-around windows (e.g. 22 → 6) are supported. */
  allowedHoursLocal?: { start: number; end: number; tz: string };

  /** Hard cap on total calls per UTC day. Counts every tool call. */
  dailyCallCap?: number;
}

Example: a research-bot key

A key for a research agent that should only run during US market hours, only validate (no proposing), and never look at crypto:

json
{
  "scopes": ["read", "validate"],
  "policy": {
    "allowedAssetTypes": ["tradfi"],
    "allowedHoursLocal": { "start": 9, "end": 16, "tz": "America/New_York" },
    "dailyCallCap": 500
  }
}

Example: a rebalance bot

A key allowed to propose trims but capped at $25k/day, only on a short list of assets, only during weekday morning hours:

json
{
  "scopes": ["read", "validate", "propose"],
  "policy": {
    "maxAmountUsdPerDay": 25000,
    "allowedAssets": ["BTC", "ETH", "SOL", "SPY", "QQQ"],
    "allowedHoursLocal": { "start": 9, "end": 12, "tz": "America/New_York" }
  }
}

Violation rule names

When a key policy blocks a call, the response carries one or more of:

  • key_policy_asset_not_allowed — symbol isn’t in allowedAssets.
  • key_policy_asset_type_not_allowed — class isn’t in allowedAssetTypes.
  • key_policy_daily_amount_cap — the cumulative amountUsd across today’s proposes would exceed maxAmountUsdPerDay.
  • key_policy_daily_call_cap — the key’s call count for today is at or above dailyCallCap.
  • key_policy_outside_hours — current local time is outside allowedHoursLocal.

Enforcement order

  • 1 · scope check at the route guard. Missing scope returns 401.
  • 2 · per-key policy check before any IPS evaluation. Cheap to compute, short-circuits expensive work if the policy blocks. The decision is audit-logged.
  • 3 · IPS guardrail evaluates the user’s mandate, drawdown, standing rules, asset authority.

A blocked per-key policy returns the violations under the same { allowed: false, violations: [...] } envelope as an IPS rejection — your agent code doesn’t need a separate branch to handle it.

Editing a policy

Policy is mutable. Edit at /agent in the AC app or via the management API. Changes take effect immediately — the next call from the key sees the new policy. Rotation is unnecessary unless the key itself was compromised.

Last updated 2026-06-15