Skip to content
Version v0.4 (draft)
ChangelogContributing

Objects

Intent

What an agent asks for.

An intent is what an agent asks for. One wire form is shared by every binding: the REST endpoints POST /v1/check and POST /v1/authorize, and the MCP tools a2m_check and a2m_place_order all take the same object.

Field Type Required Notes
intent_id string yes The caller’s idempotency key. Repeating it with the same body returns the same result; repeating it with a different body is A2M_IDEMPOTENCY (409).
venue string yes Venue name, for example hyperliquid or sim.
instrument string yes The venue’s own symbol, for example ETH on Hyperliquid perpetuals or BTC/USDT.
side string yes, except mleg buy or sell. A spread has a side per leg instead.
qty decimal string yes, unless notional Must be positive. At most 9 decimal places; more is a 400 (APEX_4011), never rounded. The venue’s lot size applies. Options: contracts; mleg: strategy units.
notional decimal string no Instead of qty, for a market order: spend (buy) or raise (sell) this much in the quote currency. The venue’s filled quantity is final.
order_type string no limit (default), market, stop, stop_limit or trailing_stop.
limit_price decimal string for limit, stop_limit At most 9 decimal places; more is a 400 (APEX_4011), never rounded. The venue’s tick applies. For mleg, the net price per unit (positive a debit, negative a credit).
stop_price decimal string for stop, stop_limit The trigger.
trail_price, trail_percent decimal string for trailing_stop Exactly one.
order_class string no simple (default), bracket (entry plus take_profit and stop_loss), oto (entry plus one exit), oco (take_profit and stop_loss closing a position), mleg (2 to 4 option legs).
take_profit object for bracket, oco; oto one of the two { "limit_price": "..." }
stop_loss object for bracket, oco; oto one of the two { "stop_price": "...", "limit_price": "..." }; limit_price makes it a stop limit.
legs array for mleg { "instrument", "ratio_qty" (integer, default 1), "side", "position_intent" }, one underlying and expiry.
position_intent string no Options: buy_to_open, buy_to_close, sell_to_open, sell_to_close.
replaces string no The client_order_id of a working order of the same agent, venue, instrument and side that this intent replaces.
time_in_force string no gtc (default), ioc, fok, post_only, day, opg, cls. See below.
reference_price decimal string see notes The agent’s view of the price. At most 9 decimal places. Ignored when the authorizer prices intents itself from a quote source.
reference_price_ts RFC 3339 string see notes Time of the reference price. A missing, unparseable, stale or future reference fails closed (A2M_STALE_PRICE). The reference implementation’s default maximum age is 10 seconds.
reduce_only boolean no Only shrink an existing position.
extended_hours boolean no Default false. When true, the order may also trade in the market’s pre- and post-market sessions. Only a limit order with day or gtc is accepted; any other combination is a 400 (APEX_4011). See Sessions and calendars.

The agent does not send a client_order_id. The authorizer mints one when it issues an executable decision. See Orders and execution reports.

The protocol values are lower case. Common aliases are accepted and normalised (alo, add_liquidity_only and postonly become post_only; good_till_cancel becomes gtc; immediate_or_cancel becomes ioc; fill_or_kill becomes fok). Any other value is a 400 error, never a silent default.

Value Meaning
gtc Good till cancelled
ioc Immediate or cancel: fill what crosses now, cancel the rest
fok Fill or kill
post_only Add liquidity only; rejected if it would cross
day Expires at the end of the venue’s trading day
opg Opening auction only
cls Closing auction only

The decision fixes the time in force and the order type; nothing downstream may change them. A venue that does not support a combination MUST refuse the order before sending it (A2M_TIME_IN_FORCE or A2M_ORDER_TYPE). It MUST NOT downgrade, coerce or substitute a supported value.

The default time_in_force is gtc. A market order that omits it is therefore gtc, and is refused on any venue that does not accept market plus gtc. The agent SHOULD set a time in force the venue accepts for that order type. For a market order, Hyperliquid accepts ioc; Alpaca accepts day (stocks and options) or gtc and ioc (crypto).

What a venue accepts is declared per asset class by its adapter (see Venue adapter contract): order types with their time in force, order classes, notional orders, replace, extended hours, maximum legs and exercise. The authorizer’s rules are venue-neutral; the executor refuses an undeclared form before sending (A2M_ORDER_TYPE, A2M_ORDER_CLASS, A2M_TIME_IN_FORCE, A2M_REPLACE, A2M_ACTION).

The authorizer judges session against the instrument’s calendar, in that calendar’s time zone.

  • Regular sessions are the market’s ordinary trading hours. An intent with extended_hours false is accepted only inside a regular session on a trading day (A2M_MARKET_CLOSED otherwise).
  • Extended sessions are the pre- and post-market periods, when the market has them. US equities in the reference data use 04:00–09:30 and 16:00–20:00 Eastern Time (17:00 on early-close days).
  • Holidays are closed for every session.
  • Early closes cut a trading day short: regular sessions end at the early close, and extended sessions end at the early extended close. The gap between the early regular close and the usual post-market start stays closed; the authorizer fails closed rather than guess.
  • A market with no extended sessions (for example a 24-hour crypto venue) refuses extended_hours true (A2M_EXTENDED_HOURS). If both regular and extended sessions are closed, the refusal is A2M_MARKET_CLOSED.
  • A missing or unreadable calendar fails closed (A2M_MARKET_CLOSED).

The executor refuses an extended-hours decision before sending (A2M_EXTENDED_HOURS, 422) unless the venue declares extended_hours in its capabilities (Alpaca does). It MUST NOT silently send the order as a regular-hours order.

Listed options are named by OCC symbol: root, expiry YYMMDD, C or P, strike times 1000 in 8 digits (SPY261218C00600000). The authorizer adds a contract to its reference data the first time it is named (multiplier 100). Allowlists match an option by its underlying. Which options an agent may open is the mandate row’s options_level; see Mandate.

POST /v1/actions with { "intent_id", "venue", "instrument", "action" } asks to exercise a long option, or tells the broker do_not_exercise it at expiry. It needs options level 2 and a long position; an exercise must also fit max_order_notional (the shares at the strike) and, for a call, the strike cash at the broker. The answer is a signed decision like an order’s, holding nothing; the shares or cash arrive as broker activity, which the authorizer books.

{
"intent_id": "demo-0001",
"venue": "hyperliquid",
"instrument": "ETH",
"side": "buy",
"qty": "0.01",
"order_type": "limit",
"limit_price": "2000",
"time_in_force": "gtc"
}

A bracket: buy at market, then sell at a take-profit or a stop loss, whichever comes first.

{
"intent_id": "demo-0002",
"venue": "alpaca",
"instrument": "AAPL",
"side": "buy",
"qty": "1",
"order_type": "market",
"time_in_force": "day",
"order_class": "bracket",
"take_profit": { "limit_price": "370" },
"stop_loss": { "stop_price": "345" }
}