Agentic Trading

The enterprise trading environment: your firm defines a strategy (the constraint envelope), a named portfolio manager grants an agent a mandate within it, and every order mints a short-lived, transaction-bound token that is re-evaluated live. Requires the capital-markets add-on. This governs agents trading your own book — for your customers' trading agents, see Consumer Delegation.

Strategies

A strategy is the firm-level envelope (org-admin authority, via /v1/trading/strategies): trading scopes, the instrument universe (opaque refs), permitted order types and sides, currency, a per-order notional cap, a windowed budget that applies across the whole strategy, trading hours in a declared IANA timezone, and optionally a PM IdP group for self-service mandates.

  • Versions are immutable. Drafts are editable; activation freezes the version forever and supersedes the prior active one. Auditors ask "which envelope governed this trade" — the token stamps the exact version, so that question always has an answer.
  • Supersession never suspends; retirement does. Mandates pin the version they were granted under and keep running when a new version activates. Retiring a version (or the whole lineage — the desk kill switch) suspends its mandates on their very next call.

Mandates & the subset rule

A mandate binds one agent to the active strategy version under one accountable PM (POST /v1/trading/mandates). It may narrow any envelope dimension — fewer instruments, buy-only, a lower cap, its own budget, tighter windows — and is always a subset of its pinned version: validated at grant with every violation reported at once. Mandates are immutable after grant except revocation (revoke and re-grant to change), and one live mandate exists per agent per strategy — exactly one accountable human.

Who can grant: an org admin naming any active member as PM, or — when the strategy sets a PM IdP group — a member holding that group live, naming themselves. The group is then a liveness condition: losing it in your IdP suspends the mandate with no API call. Revoke = the PM or an admin. PMs see their book at GET /v1/me/mandates.

Lifecycle & the kill-switch contract

Everything except explicit revocation is live-evaluated, at every mint and every introspection — nothing depends on a background job or a webhook landing:

  • PM offboarded (SCIM or admin) → next call refuses.
  • PM loses the strategy's IdP group → next call refuses.
  • Strategy version or lineage retired → next call refuses.
  • Mandate expired, add-on lapsed, or agent suspended → next call refuses.
  • Trading window closes mid-token → the next introspection refuses, inside the token's own lifetime.

Suspension webhooks fire for the two explicit bulk acts (strategy retirement, PM offboard) so desk observability sees them as one event — enforcement never waits for them.

Minting & introspection

POST /v1/oauth/token with the agent's credential as client assertion and mandate_id. Execute-tier scopes require exactly one RFC 9396 authorization_details entry of type trade_order naming the exact order (instrument, side, order type, notional; limit price for priced orders). The mint validates the order against the mandate's effective constraints, enforces both budget walls (the mandate's, and the strategy's across the whole lineage), reserves the notional immediately, and returns a 5-minute token whose subject is the agent — with the mandate, the exact strategy version, and the accountable PM carried as claims.

  • No fallback authority. Scope comes only from the mandate — an agent with no declared scopes anywhere still receives only mandate scopes on this path.
  • Introspection is the enforcement point (RFC 7662): the mandate is re-evaluated live on every call, including the trading windows. Verify tokens by introspection, not local JWT checks.
  • Report fills to POST /v1/trading/mandates/{ref}/usage with the token's jti — the reserving hold flips to the executed amount (partial fills report what actually executed).

The full reference for this surface is delivered to customers under NDA.

Web execution

With the org opt-in on (PUT /v1/trading/web-execution, admin, requires the trading environment), mandates execute at web trading platforms through the eniyan-web browser gate with full parity: web orders ride mandate math only — budgets, per-order caps, instrument lists, windows, the strategy subset rule — and a refusal is final, exactly as at the API. The venue is bound by the agent’s web allowlist (the Pay / Transact ability on the site), the gate reports fills by the mint’s jti so the reserving hold flips to the executed amount, and turning the toggle off stops web orders on the gate’s next config sync. Note: delegation counterparty allow-lists have no counterparty dimension for trades — a consumer delegation carrying ANY counterparty allow-list refuses all trade orders (existing behavior); keep trading-scope delegations counterparty-free.

Refusal codes

CodeWhen
mandate_unknownNo such mandate for this agent in your org.
mandate_not_live: <reason>The mandate lapsed — mandate_revoked, mandate_expired, mandate_pm_inactive (PM offboarded), mandate_pm_group_lost (PM lost the strategy's IdP group), strategy_retired, trading_not_enabled (add-on lapsed), trading_agent_disabled (personal accounts: the agent's Trading switch is off — switching it back on resumes the mandate), or agent_not_active.
invalid_scopeNo requested scope is granted by the mandate. There is no fallback: this path never echoes a request.
jit_suspendedA JIT-mode agent has no active task window (both authorities must agree).
outside_trading_windowThe mint falls outside the mandate's (or strategy's) trading hours; the detail carries the next window-open time.
instrument_not_allowed / side_not_allowed / order_type_not_allowedThe order is outside the mandate's effective instrument list, sides, or order types.
currency_mismatchThe order currency does not match the strategy.
amount_exceeds_capNotional above the effective per-order cap.
mandate_budget_exceeded / strategy_budget_exceededThe windowed notional budget is exhausted — at the mandate level, or across the WHOLE strategy lineage (every mandate, every version).

Every refusal is written to your audit log with its reason — refusal evidence is part of the product, not an error path.

Roles

  • Org admin — create/edit strategy drafts, activate, retire; name any active member as a mandate's PM; revoke any mandate.
  • Portfolio manager — any active member named on a mandate; self-service grants when they hold the strategy's PM IdP group; revoke their own mandates; /v1/me/mandates.
  • Members — read access to strategies and mandates (each row carries its live state and reason).

Personal accounts

Personal accounts get the SAME strategy and mandate machinery — you are the admin and your own PM — with one addition: an explicit per-agent Trading switch on the agent's page, at $5/month per trading agent (stacking with the $2/agent overage; enabling the trading environment itself costs nothing). On personal accounts a mandate can only be granted to a switched-on agent (TRADING_AGENT_NOT_ENABLED), and the switch is a mandate-liveness leg: switching it off refuses the very next order (trading_agent_disabled) with billing stopping at the next sync; switching back on resumes the mandate — no reinstatement ceremony. Enterprise accounts have no switch and no per-agent trading fee — the switch routes themselves return PERSONAL_ONLY on a team account.