{"openapi":"3.0.3","info":{"title":"BitGo FIX API","version":"0.3.0","x-api-protocol":"fix","x-source-location":"https://github.com/BitGo/trade-services/blob/master/packages/lumina-fix-server/api/trade-fix.yaml","x-team":"@BitGo/prime-trade","description":"## Overview\n\nThe BitGo FIX API provides a standard **FIX 4.4** interface for institutional order execution\nand real-time market data. It supports persistent **TLS/TCP** sessions with heartbeat-based\nconnection monitoring, typed message validation, and real-time fill delivery.\n\n**Supported capabilities:**\n- **Order types:** Market, Limit, TWAP, SteadyPace, Stop (stop-market and stop-limit)\n- **Order actions:** New orders, cancellations, status queries\n- **Market data:** Level 2 orderbook snapshots, incremental updates, subscription management\n- **Funding:** Funded and margin orders\n\n**Session model:** BitGo uses a stateless session model. Sequence numbers reset on every\nconnection. Clients must reconnect with `ResetSeqNumFlag=Y` and reconcile via REST on reconnect.\n`ResendRequest` is not supported.\n\n## Prerequisites\n\n### FIX API License\n\nYour enterprise must have the FIX API license enabled. Contact your BitGo account manager or\nBitGo support to request activation.\n\n### Access Token with FIX Scope\n\nGenerate an access token with the following permissions in the BitGo UI or via the\n[REST API](https://developers.bitgo.com/reference/v2accesstokenadd):\n\n| Permission | Scope |\n|---|---|\n| Prime - FIX Trading API | `trade_fix` |\n| Prime - View Trades | `trade_view` |\n| Prime - Perform Trades | `trade_trade` |\n\nSave the token securely. It will be used as the `Password` (Tag 554) in your FIX Logon message.\n\n> **Note:** The access token is generated by you in the BitGo UI. It is **not** issued by BitGo support.\n\n### Account ID\n\nYour Go Account ID (32-character hex string, e.g. `0123456789abcdef0123456789abcdef`) is used as\nyour `SenderCompID` (Tag 49) on every FIX message. You can find this in the BitGo UI.\n\n### IP Whitelisting\n\n**ACTION REQUIRED:** Provide your static outbound IP address(es) to your BitGo account\nrepresentative before onboarding. Only whitelisted IPs can access the FIX service and\nestablish a FIX session.\n\n> **Note:** Allow 1 business day for IP provisioning. If your egress IP changes after\n> onboarding, notify BitGo immediately to avoid connectivity outages.\n\n## Connection Details\n\n### Production\n\n| Setting | Value |\n|---|---|\n| Endpoint | `fix.bitgo.com:5100` |\n| Protocol | FIX 4.4 over TCP |\n\n### Test Sandbox\n\n| Setting | Value |\n|---|---|\n| Endpoint | `fix.bitgo-test.com:5100` |\n| Protocol | FIX 4.4 over TCP |\n\n### Session Types\n\nBitGo supports two session types per enterprise, distinguished by `TargetCompID`:\n\n| Session Type | TargetCompID | Purpose |\n|---|---|---|\n| Order Flow | `BITGO` | Order submission, cancellation, status queries, execution reports |\n| Market Data | `BITGO-MD` | Orderbook snapshots, incremental updates, subscription management |\n\nBoth sessions share the same hostname and port. Your enterprise may hold one order session and\none market data session simultaneously. Session type determines intended use and rate-limit\nscope.\n\n> **Note:** ExecutionReports (`35=8`), OrderCancelRejects (`35=9`), and all order lifecycle\n> messages are delivered only on the `BITGO` session. The `BITGO-MD` session receives no\n> order-related messages.\n\n## Maintenance Window\n\nFIX sessions operate **24/7**. Planned maintenance occurs during the following windows:\n\n**Deployments:** Monday – Friday, **01:30 – 01:50 ET**. During this window the server sends\nLogout with `Text=\"server draining, please reconnect\"`. Reconnect immediately — a new pod will\naccept the connection. Reconcile open orders via REST after reconnecting.\n\n**Timestamps:** All timestamps are UTC, FIX 4.4 format `YYYYMMDD-HH:MM:SS[.sss[sss]]`.\nSeconds (`20260415-14:30:00`), milliseconds (`20260415-14:30:00.123`), and microseconds\n(`20260415-14:30:00.163512`) are all accepted.\n"},"servers":[{"url":"fix.bitgo.com:5100","description":"Production FIX gateway (**TLS/TCP**). This specification documents FIX message formats.\n"}],"paths":{"/fix/admin (header and trailer)":{"get":{"x-internal":false,"summary":"Header & Trailer","description":"The baseline specification for this API is **FIX 4.4**. A standard header must be present at the\nstart of every message in both directions. A standard trailer must be present at the end.\n\nAll messages sent in either direction must contain `SenderCompID` (49) and `TargetCompID` (56).\n`SenderCompID` is your 32-character hex Go Account ID. `TargetCompID` is `BITGO` for order entry\nor `BITGO-MD` for market data.\n\n**Timestamp format:** UTC only, `YYYYMMDD-HH:MM:SS[.sss[sss]]`. Seconds, milliseconds, and\nmicroseconds are all supported. No timezone suffix.\n","operationId":"trade.fix.admin.headerAndTrailer","tags":["Accounts FIX"],"responses":{"200":{"description":"Standard Header and Trailer fields present on every FIX message.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/StandardHeader"},{"$ref":"#/components/schemas/StandardTrailer"}]}}}}}}},"/fix/admin (logon)":{"post":{"x-internal":false,"summary":"Logon (35=A)","description":"The client sends Logon (`35=A`) to the server over TLS/TCP at `fix.bitgo.com:5100`\n(or test). This is **not** an HTTP request.\n\nRequired before order entry or market-data application messages on a new session. One active\norder-entry session per Go Account (`56=BITGO`); market data uses a separate session\n(`56=BITGO-MD`).\n\n`SenderCompID` (49) identifies the account; there is no separate Username (tag 553).\nYour access token goes in `Password` (554).\n\n**On success:** server echoes Logon (`35=A`).\n\n**On failure:** server sends **Logout** (`35=5`) with `Text` (58) describing the reason.\nThe session does not reach the logged-on state. Common rejection texts:\n\n| Text (tag 58) | Cause |\n|---|---|\n| `invalid access token` | Token malformed, expired at Logon, or otherwise invalid |\n| `missing or empty access token (tag 554)` | Tag 554 absent or empty |\n| `invalid Go Account ID in TargetCompID: expected 32 hex chars` | Bad account ID format (swapped CompIDs) |\n| `unknown SenderCompID: expected BITGO or BITGO-MD` | Wrong session type in tag 56 (or swapped 49/56) |\n| `token missing trade_fix scope` | Token lacks FIX permission |\n| `not authorised for this account` | No spend permission on the account |\n| `rate limit exceeded on logon, retry shortly` | More than 10 Logon attempts per minute |\n| `authentication failed` | Generic auth failure |\n| `access token expired` | Token already expired at Logon |\n| `active session exists for this account` | Another FIX session is already active for this account |\n| `session enforcement failed` | Session store could not claim the account slot |\n| `server shutting down, please reconnect` | Acceptor is draining / shutting down |\n\nMid-session token expiry and revocation use Logout (`35=5`) with `session expired` /\n`access token revoked` (see Logout page), not these Logon reject texts.\n\n**Example (pipe-delimited FIX):**\n\n```\n8=FIX.4.4|9=128|35=A|49=0123456789abcdef0123456789abcdef|56=BITGO|34=1|554=v2_your_access_token_here|141=Y|98=0|108=30|52=20260415-14:30:00.000|10=XXX|\n```\n","operationId":"trade.fix.admin.logon","x-fix-msg-type":"A","tags":["Accounts FIX"],"requestBody":{"required":true,"description":"Logon (`35=A`) body tags. Standard header/trailer tags are also required on every message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogonMessage"}}}},"responses":{"200":{"description":"Session established. Server echoes Logon (`35=A`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LogonMessage"}}}},"default":{"description":"Logout (`35=5`) with rejection reason in tag `58`."}}}},"/fix/admin (session reject)":{"get":{"x-internal":false,"summary":"Session Reject (35=3)","description":"Server → client **Session Reject** (`35=3`). Sent when a received FIX message is malformed or\nviolates session-level protocol rules. This is a **session-level** reject, distinct from\nbusiness-level rejects, which use ExecutionReport (`35=8`, `150=8`) or OrderCancelReject (`35=9`).\n\nOn receiving a Session Reject, fix the offending message and resend. Common reasons:\n\n| SessionRejectReason (373) | Meaning |\n|---|---|\n| `0` | Invalid tag number |\n| `1` | Required tag missing |\n| `5` | Value out of range or incorrect |\n| `6` | Incorrect format |\n| `11` | Invalid MsgType |\n| `99` | Other |\n","operationId":"trade.fix.admin.sessionReject","x-fix-msg-type":"3","tags":["Accounts FIX"],"responses":{"200":{"description":"Session Reject (`35=3`) field reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionReject"}}}}}}},"/fix/admin (heartbeat)":{"get":{"x-internal":false,"summary":"Heartbeat (35=0)","description":"Heartbeat (`35=0`) is exchanged in both directions over TLS/TCP. This is not an HTTP request.\n\nThe server and client exchange Heartbeats every `HeartBtInt` seconds (must be `30`).\nIf the server does not receive a Heartbeat within the expected interval, it sends a\n**TestRequest** (`35=1`). If the client does not respond, the session is disconnected.\n\n**Conditional:** `TestReqID` (112) is required when this Heartbeat is a response to a\nTestRequest; otherwise omit it.\n","operationId":"trade.fix.admin.heartbeat","x-fix-msg-type":"0","tags":["Accounts FIX"],"requestBody":{"required":false,"description":"Heartbeat body tags (usually empty unless responding to TestRequest).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Heartbeat"}}}},"responses":{"200":{"description":"Heartbeat acknowledged / exchanged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Heartbeat"}}}}}}},"/fix/admin (test request)":{"get":{"x-internal":false,"summary":"Test Request (35=1)","description":"Either side may send TestRequest (`35=1`) to force a Heartbeat response from the other.\n\nThe counterparty must reply with Heartbeat (`35=0`) echoing the same `TestReqID` (112).\n","operationId":"trade.fix.admin.testRequest","x-fix-msg-type":"1","tags":["Accounts FIX"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestRequest"}}}},"responses":{"200":{"description":"Expect Heartbeat (`35=0`) with matching TestReqID (112).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Heartbeat"}}}}}}},"/fix/admin (logout)":{"get":{"x-internal":false,"summary":"Logout (35=5)","description":"Either side may initiate a clean disconnect by sending Logout (`35=5`).\n\nThe server also sends Logout for session-level problems:\n\n| Text (58) | Cause |\n|---|---|\n| `session expired` | Access token expired mid-session |\n| `access token revoked` | Token revoked (e.g. via BitGo UI) |\n| `server draining, please reconnect` | Maintenance / pod drain (Mon–Fri 01:30–01:50 ET) |\n\nLogon failures also arrive as Logout (`35=5`) with `Text` (58) before the session is\nestablished (see Logon page) — including `server shutting down, please reconnect` when\nthe acceptor is draining and rejects a new Logon.\n\n**Examples (pipe-delimited FIX):**\n\nClient-initiated Logout (client → server). `Text` (58) is optional:\n```\n8=FIX.4.4|9=81|35=5|34=10|49=0123456789abcdef0123456789abcdef|56=BITGO|52=20260415-14:32:10.000|10=XXX\n```\n\nServer confirms Logout (server → client):\n```\n8=FIX.4.4|9=81|35=5|34=11|49=BITGO|56=0123456789abcdef0123456789abcdef|52=20260415-14:32:10.050|10=XXX\n```\n\nServer-initiated Logout — session expired (server → client):\n```\n8=FIX.4.4|9=100|35=5|34=42|49=BITGO|56=0123456789abcdef0123456789abcdef|52=20260415-15:00:00.000|58=session expired|10=XXX\n```\n","operationId":"trade.fix.admin.logout","x-fix-msg-type":"5","tags":["Accounts FIX"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Logout"}}}},"responses":{"200":{"description":"Logout / session terminated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Logout"}}}}}}},"/fix/trading (new order single)":{"post":{"x-internal":false,"summary":"New Order Single (35=D)","description":"The client sends NewOrderSingle (`35=D`) to the server over TLS/TCP. This is not an HTTP request.\n\nPlace a new trade order on the order-entry session (`56=BITGO`). Order types and business\nvalidation match Prime REST order placement — including Market, Limit, TWAP, SteadyPace, and\nStop. See [Place Order](https://developers.bitgo.com/reference/tradeordersadd) for the full\nREST order catalog; the same order types are supported over FIX.\n\nBoth buy and sell support base- and quote-denominated sizing via `OrderQty` (38) and\n`Currency` (15). The server responds with one or more ExecutionReports (`35=8`) on the same session.\nProduct minimum order sizes and quantity precision are not exposed via FIX; obtain\nthem from the Products REST endpoint\n([List Products](https://developers.bitgo.com/reference/tradeproducts)).\n\n**Examples (pipe-delimited FIX):**\n\nMarket buy $250 notional (funded):\n```\n8=FIX.4.4|9=156|35=D|49=0123456789abcdef0123456789abcdef|56=BITGO|34=5|52=20260415-14:30:00.123|11=ord-001|55=TBTC-TUSD*|54=1|40=1|38=250|15=TUSD*|60=20260415-14:30:00.123|10=XXX\n```\n\nLimit buy GTC (funded):\n```\n8=FIX.4.4|9=194|35=D|34=33|49=0123456789abcdef0123456789abcdef|52=20260511-11:57:46.396|56=BITGO|11=limit-gtc-funded-001|15=TBTC|38=0.001|40=2|44=83220.0|54=1|55=TBTC-TUSD*|59=1|60=20260511-13:00:02.000|5001=1|10=XXX\n```\n\nTWAP sell 60min (time-sliced):\n```\n8=FIX.4.4|9=234|35=D|49=0123456789abcdef0123456789abcdef|56=BITGO|34=8|52=20260415-15:07:16.163|11=ord-003|55=TBTC-TUSD*|54=2|38=0.002|15=TBTC|40=1|847=T|60=20260415-15:07:16.163|957=3|958=Duration|960=60|958=IsTimeSliced|960=true|958=Interval|960=5|10=XXX\n```\n\nStop market sell:\n```\n8=FIX.4.4|9=166|35=D|49=0123456789abcdef0123456789abcdef|56=BITGO|34=9|52=20260415-15:10:00.000|11=ord-006|55=TBTC-TUSD*|54=2|40=3|38=0.001|15=TBTC|99=48000|60=20260415-15:10:00.000|10=XXX\n```\n\nSteadyPace buy:\n```\n8=FIX.4.4|9=245|35=D|49=0123456789abcdef0123456789abcdef|56=BITGO|34=12|52=20260415-15:12:00.000|11=ord-004|55=TBTC-TUSD*|54=1|38=0.001|15=TBTC|40=1|847=S|60=20260415-15:12:00.000|957=3|958=Interval|960=5|958=IntervalUnit|960=minute|958=SubOrderSize|960=0.0002|10=XXX\n```\n\nMargin market buy $250:\n```\n8=FIX.4.4|9=164|35=D|49=0123456789abcdef0123456789abcdef|56=BITGO|34=10|52=20260415-14:30:00.789|11=ord-008|55=TBTC-TUSD*|54=1|40=1|38=250|15=TUSD*|5001=2|60=20260415-14:30:00.789|10=XXX\n```\n","operationId":"trade.fix.trading.newOrderSingle","x-fix-msg-type":"D","tags":["Orders FIX"],"requestBody":{"required":true,"description":"NewOrderSingle (`35=D`) body tags. Each property title is `Tag Name` (e.g. `38 OrderQty`).\nStandard header/trailer tags are also required on every message.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewOrderSingle"}}}},"responses":{"200":{"description":"Accepted or working; further ExecutionReports may follow.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionReport"}}}},"default":{"description":"Rejected (`150=8`, `39=8`). Check `ordRejReason` (103) and `text` (58)."}}}},"/fix/trading (order cancel request)":{"post":{"x-internal":false,"summary":"Order Cancel Request (35=F)","description":"The client sends OrderCancelRequest (`35=F`) to the server over TLS/TCP. This is not an HTTP request.\n\nCancel an open order on the order-entry session.\n\nProvide OrderID (`37`) and/or OrigClOrdID (`41`); at least one is required. Tag `37` takes\nprecedence when both are supplied.\n\n**On success:** server sends **PendingCancel** ExecutionReport (`150=6`, `39=6`) then\n**Canceled** ExecutionReport (`150=4`, `39=4`). `LeavesQty` (151) on the Canceled report is\nthe open quantity at cancel time, **not** `0`. Detect completion via `OrdStatus` (39) or\n`ExecType` (150), not `151=0`.\n\n**On failure:** server sends **OrderCancelReject** (`35=9`). Check `CxlRejReason` (102) and\n`Text` (58).\n\n**Examples (pipe-delimited FIX):**\n\nCancel by OrigClOrdID:\n```\n8=FIX.4.4|9=132|35=F|49=0123456789abcdef0123456789abcdef|56=BITGO|34=91|52=20260618-12:46:28.424|11=cxl-ord-006|41=ord-006|60=20260618-12:46:28.424|10=XXX\n```\n\nCancel by OrderID:\n```\n8=FIX.4.4|9=161|35=F|49=0123456789abcdef0123456789abcdef|56=BITGO|34=92|52=20260618-12:46:29.000|11=cxl-ord-007|37=80115a50-1542-48b7-92f9-03d99194ade3|60=20260618-12:46:29.000|10=XXX\n```\n","operationId":"trade.fix.trading.orderCancelRequest","x-fix-msg-type":"F","tags":["Orders FIX"],"requestBody":{"required":true,"description":"OrderCancelRequest (`35=F`) body tags. Each property title is `Tag Name`.\nStandard header/trailer tags are also required on every message.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCancelRequest"}}}},"responses":{"200":{"description":"Cancel accepted. PendingCancel then Canceled ExecutionReports follow.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionReport"}}}},"default":{"description":"Cancel refused. The server responds with OrderCancelReject (`35=9`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCancelReject"}}}}}}},"/fix/trading (order cancel reject)":{"get":{"x-internal":false,"summary":"Order Cancel Reject (35=9)","description":"The server sends OrderCancelReject (`35=9`) to the client over TLS/TCP. This is not an HTTP response.\n\nSent when an OrderCancelRequest cannot be fulfilled. For example, the order is already\nfilled, already canceled, or unknown.\n\n`CxlRejResponseTo` (434) is always `1` (OrderCancelRequest).\n\n| CxlRejReason (102) | Meaning |\n|---|---|\n| `0` | Too late to cancel. Order already filled, canceled, or pending cancel |\n| `1` | Unknown order. OrigClOrdID (41) or OrderID (37) not found |\n| `99` | Other. System error, account mismatch, or non-cancelable state (see `text` 58) |\n\n**Example (pipe-delimited FIX)** — too late to cancel (order already canceled; `39`\nis the order's current status). Same shape when already filled (`39=2`):\n```\n8=FIX.4.4|9=250|35=9|34=67|49=BITGO|52=20260728-06:18:59.380|56=0123456789abcdef0123456789abcdef|1=0123456789abcdef0123456789abcdef|11=cxl-ord-008|37=16cebd5d-dc6a-4cdc-b72f-0bbbf49eabe1|39=4|41=NONE|58=order cannot be cancelled|60=20260728-06:18:59.228|102=0|434=1|10=XXX\n```\n","operationId":"trade.fix.trading.orderCancelReject","x-fix-msg-type":"9","tags":["Orders FIX"],"responses":{"200":{"description":"OrderCancelReject (`35=9`) field reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderCancelReject"}}}}}}},"/fix/trading (order status request)":{"post":{"x-internal":false,"summary":"Order Status Request (35=H)","description":"The client sends OrderStatusRequest (`35=H`) to the server over TLS/TCP. This is not an HTTP request.\n\nRequest a point-in-time order snapshot. The server responds with a single **ExecutionReport**\n(`35=8`, `150=I`) containing current quantity, status, and fill fields.\n\nProvide tag `37` (OrderID) and/or tag `11` (ClOrdID). At least one is required; `37` takes\nprecedence when both are supplied.\n\nOn failure (order not found) the server responds with an ExecutionReport reject:\n`150=8`, `39=8`, `37=NONE`, `55=N/A`, `54=7`, `103=99`, `58=\"order not found\"`.\n\n**Example (pipe-delimited FIX):**\n```\n8=FIX.4.4|9=146|35=H|49=0123456789abcdef0123456789abcdef|56=BITGO|34=118|52=20260618-12:59:17.539|11=limit-gtc-funded-001|37=96b407cf-ec38-404c-b849-0d53f1ee923b|10=XXX\n```\n","operationId":"trade.fix.trading.orderStatusRequest","x-fix-msg-type":"H","tags":["Orders FIX"],"requestBody":{"required":true,"description":"OrderStatusRequest (`35=H`) body tags. Each property title is `Tag Name`.\nStandard header/trailer tags are also required on every message.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatusRequest"}}}},"responses":{"200":{"description":"Status as ExecutionReport (`150=I`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionReport"}}}}}}},"/fix/trading (execution report)":{"get":{"x-internal":false,"summary":"Execution Report (35=8)","description":"The server sends ExecutionReport (`35=8`) to the client over TLS/TCP. This is not an HTTP response.\n\nSent in response to New Order Single, Order Cancel Request, and Order Status Request. Also\nsent unsolicited for fills and terminal state transitions.\n\n**Exec types (tag 150):**\n\n| ExecType | Name | Description |\n|---|---|---|\n| `A` | PendingNew | Order received, not yet active |\n| `0` | New | Order live with no fills |\n| `F` | Trade | Fill (partial or completing). Use `OrdStatus` (39) and `LeavesQty` (151) for working vs terminal state — not `150=F` alone. Completing fill often still `39=1` with `151=0`; terminal Filled (`39=2`) typically on following `150=I` |\n| `6` | PendingCancel | Cancel request received, awaiting confirmation |\n| `4` | Canceled | Order canceled (may include partial fills). System-initiated cancels carry the client-facing cancellation reason on `Text` (58) |\n| `8` | Rejected | Order rejected; see `OrdRejReason` (103) and `Text` (58) |\n| `I` | Order Status | Response to OrderStatusRequest (`35=H`). Also sent as a terminal status summary after the order is fully filled (following fill reports with `150=F`). For canceled orders, carries the cancellation reason on `Text` (58) |\n\n**Fill reports** (`150=F`) include `lastQty` (32) and `lastPx` (31) for the individual fill,\nplus running totals on `cumQty` (14) and `avgPx` (6). Both partial and completing fills use\n`150=F`. Use `OrdStatus` (39) and `LeavesQty` (151) for working vs terminal state — not\n`ExecType` alone. The last fill often still reports `39=1` even when `151=0`; terminal\n**Filled** (`39=2`, typically with `151=0`) arrives on the following Order Status report\n(`150=I`), not on the fill itself.\n\n**Reject reports** (`150=8`, `39=8`) include `ordRejReason` (103) and `text` (58).\n\n**Cancel reports:** `LeavesQty` (151) on the Canceled report (`150=4`) stays at the open\nquantity at cancel time; it is **not** reset to `0`. Use `OrdStatus` (39) together with\n`LeavesQty` (151) for terminal-state detection — `39=4` is canceled even when `151` > `0`.\nSystem-initiated Canceled reports (e.g. an asynchronous reservation failure after\nPendingNew) include `text` (58) carrying the client-facing cancellation reason (e.g.\n`Insufficient balance for reservation`); user-initiated cancels omit `text` (58).\n\n**OrdStatus (tag 39):**\n\n| Value | Name |\n|---|---|\n| `A` | Pending New |\n| `0` | New |\n| `1` | Partially Filled |\n| `2` | Filled |\n| `4` | Canceled |\n| `6` | Pending Cancel |\n| `8` | Rejected |\n\n**OrdRejReason (tag 103)** on rejects: `1` Unknown symbol, `2` Market unavailable,\n`3` OrderExceedsLimit, `6` Duplicate ClOrdID, `15` UnknownAccount, `99` Other (see Text).\n\n**Examples (pipe-delimited FIX)** for a limit GTC funded buy:\n\nPendingNew (`150=A`, `39=A`):\n```\n8=FIX.4.4|9=343|35=8|34=83|49=BITGO|52=20260618-12:37:15.365|56=0123456789abcdef0123456789abcdef|1=0123456789abcdef0123456789abcdef|6=0|11=limit-gtc-funded-004|14=0|15=TBTC|17=afd7ea59-2d0b-4ec2-83ee-637ed1ad8f73|37=96b407cf-ec38-404c-b849-0d53f1ee923b|38=0.001|39=A|40=2|44=83220|54=1|55=TBTC-TUSD*|59=1|60=20260618-12:37:15.292|150=A|151=0.001|381=0|5001=1|10=XXX\n```\n\nNew (`150=0`, `39=0`):\n```\n8=FIX.4.4|9=343|35=8|34=84|49=BITGO|52=20260618-12:37:15.494|56=0123456789abcdef0123456789abcdef|1=0123456789abcdef0123456789abcdef|6=0|11=limit-gtc-funded-004|14=0|15=TBTC|17=bb641166-c7d5-469a-9354-26133386e67f|37=96b407cf-ec38-404c-b849-0d53f1ee923b|38=0.001|39=0|40=2|44=83220|54=1|55=TBTC-TUSD*|59=1|60=20260618-12:37:15.487|150=0|151=0.001|381=0|5001=1|10=XXX\n```\n\nFill (`150=F`, `39=1`). Completing fills may still show `39=1` with `151=0`; terminal Filled is on `150=I`:\n```\n8=FIX.4.4|9=369|35=8|34=85|49=BITGO|52=20260618-12:37:15.719|56=0123456789abcdef0123456789abcdef|1=0123456789abcdef0123456789abcdef|6=64310|11=limit-gtc-funded-004|14=0.001|15=TBTC|17=b4ced93f-e9d1-4c75-ac6d-272630d02c0f|31=64310|32=0.001|37=96b407cf-ec38-404c-b849-0d53f1ee923b|38=0.001|39=1|40=2|44=83220|54=1|55=TBTC-TUSD*|59=1|60=20260618-12:37:15.638|150=F|151=0|381=64.31|5001=1|10=XXX\n```\n\nOrder Status (`150=I`, `39=2`) after a full fill (terminal Filled). Also used as the response to OrderStatusRequest (`35=H`):\n```\n8=FIX.4.4|9=351|35=8|34=86|49=BITGO|52=20260618-12:37:15.756|56=0123456789abcdef0123456789abcdef|1=0123456789abcdef0123456789abcdef|6=64310|11=limit-gtc-funded-004|14=0.001|15=TBTC|17=ba23f31a-92a0-4774-8fe4-2a730a38a904|37=96b407cf-ec38-404c-b849-0d53f1ee923b|38=0.001|39=2|40=2|44=83220|54=1|55=TBTC-TUSD*|59=1|60=20260618-12:37:15.751|150=I|151=0|381=64.31|5001=1|10=XXX\n```\n\nReject (`150=8`, `39=8`), e.g. order not found on status request:\n```\n8=FIX.4.4|9=177|35=8|34=7|49=BITGO|52=20260528-12:00:00.001|56=0123456789abcdef0123456789abcdef|150=8|39=8|11=8b1d4f55-6e7c-4a8d-9b02-1c3d5e7f9000|37=NONE|55=N/A|54=7|103=99|58=order not found|10=XXX\n```\n\nPendingCancel (`150=6`, `39=6`) then Canceled (`150=4`, `39=4`).\nNote: `11` (ClOrdID) is `NONE` on server-generated cancel reports; `41` (OrigClOrdID) carries the original client order ID.\n`151` (LeavesQty) reflects the open quantity at cancel time and is not reset to `0`:\n```\n8=FIX.4.4|9=323|35=8|49=BITGO|56=0123456789abcdef0123456789abcdef|34=105|52=20260618-12:46:28.719|1=0123456789abcdef0123456789abcdef|6=0|11=NONE|14=0|15=TBTC|17=exec-pending-cxl|37=80115a50-1542-48b7-92f9-03d99194ade3|38=0.001|39=6|40=3|41=doc-ord-006|54=2|55=TBTC-TUSD*|59=1|60=20260618-12:46:28.685|99=48000|150=6|151=0.001|381=0|5001=1|10=XXX\n```\n```\n8=FIX.4.4|9=320|35=8|49=BITGO|56=0123456789abcdef0123456789abcdef|34=106|52=20260618-12:46:28.953|1=0123456789abcdef0123456789abcdef|6=0|11=NONE|14=0|15=TBTC|17=exec-canceled|37=80115a50-1542-48b7-92f9-03d99194ade3|38=0.001|39=4|40=3|41=doc-ord-006|54=2|55=TBTC-TUSD*|59=1|60=20260618-12:46:28.948|99=48000|150=4|151=0.001|381=0|5001=1|10=XXX\n```\n\nSystem-initiated Canceled (`150=4`, `39=4`) after PendingNew, e.g. an asynchronous\nreservation failure — `text` (58) carries the client-facing cancellation reason:\n```\n8=FIX.4.4|9=360|35=8|49=BITGO|56=0123456789abcdef0123456789abcdef|34=107|52=20260618-12:46:28.953|1=0123456789abcdef0123456789abcdef|6=0|11=NONE|14=0|15=TBTC|17=exec-canceled|37=80115a50-1542-48b7-92f9-03d99194ade3|38=0.001|39=4|40=3|41=doc-ord-006|54=2|55=TBTC-TUSD*|58=Insufficient balance for reservation|59=1|60=20260618-12:46:28.948|99=48000|150=4|151=0.001|381=0|5001=1|10=XXX\n```\n","operationId":"trade.fix.trading.executionReport","x-fix-msg-type":"8","tags":["Orders FIX"],"responses":{"200":{"description":"ExecutionReport (`35=8`) field reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionReport"}}}}}}},"/fix/market-data (market data request)":{"post":{"x-internal":false,"summary":"Market Data Request (35=V)","description":"The client sends MarketDataRequest (`35=V`) to the server over TLS/TCP. This is not an HTTP request.\n\nSubscribe to or snapshot an order book on a **market data session** (`56=BITGO-MD`),\nseparate from the order-entry session (`BITGO`).\n\n**Subscribe:** set `263=1` and `265=1`. Tag `262` (MDReqID) must be unique per subscription.\nTag `264` (MarketDepth): `0` = full book (up to 100 levels per side), `1`–`100` = top N.\nValues of 101+ are rejected (`281=5`).\n\n**Snapshot only:** set `263=0` for a one-time snapshot with no ongoing subscription.\n\n**Unsubscribe:** send `263=2` with the same `262` used at subscription time.\n\n**Responses:** initial **MarketDataSnapshotFullRefresh** (`35=W`), then **Incremental Refresh**\n(`35=X`) on updates (~300 ms cycle), or **MarketDataRequestReject** (`35=Y`) on error.\n\n**Subscription limits:** 50 active subscriptions per session; 20 symbols per single request;\n100 total symbols per enterprise across all sessions.\n\n**Gap detection:** tag 83 (RptSeq) is not present on `35=X`. Use session-level MsgSeqNum (34)\nfor gap detection. QuickFIX manages this automatically. On gap, resubscribe with `263=1`.\n\n**Examples (pipe-delimited FIX):**\n\nSubscribe to BTC-USD top 10 levels (incremental):\n```\n8=FIX.4.4|9=152|35=V|49=0123456789abcdef0123456789abcdef|56=BITGO-MD|34=5|52=20260415-14:30:00.000|262=md-req-001|263=1|264=10|265=1|267=2|269=0|269=1|146=1|55=BTC-USD|10=XXX\n```\n\nSnapshot only (no ongoing subscription):\n```\n8=FIX.4.4|9=145|35=V|49=0123456789abcdef0123456789abcdef|56=BITGO-MD|34=6|52=20260415-14:30:01.000|262=md-req-002|263=0|264=1|267=2|269=0|269=1|146=1|55=ETH-USD|10=XXX\n```\n\nUnsubscribe:\n```\n8=FIX.4.4|9=145|35=V|49=0123456789abcdef0123456789abcdef|56=BITGO-MD|34=7|52=20260415-14:30:02.000|262=md-req-003|263=2|264=1|267=2|269=0|269=1|146=1|55=BTC-USD|10=XXX\n```\n","operationId":"trade.fix.marketData.marketDataRequest","x-fix-msg-type":"V","tags":["Market Data FIX"],"requestBody":{"required":true,"description":"MarketDataRequest (`35=V`) body tags. Each property title is `Tag Name`.\nStandard header/trailer tags are also required on every message. Use TargetCompID `BITGO-MD`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataRequest"}}}},"responses":{"200":{"description":"Subscription active; MarketDataSnapshotFullRefresh follows, then incremental updates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataSnapshotFullRefresh"}}}},"default":{"description":"MarketDataRequestReject (`35=Y`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataRequestReject"}}}}}}},"/fix/market-data (market data snapshot)":{"get":{"x-internal":false,"summary":"Market Data Snapshot Full Refresh (35=W)","description":"The server sends MarketDataSnapshotFullRefresh (`35=W`) to the client over TLS/TCP. This is not an HTTP response.\n\nSent immediately when a market data subscription is activated or in response to a snapshot-only\nrequest. Contains all bid and offer levels up to the requested depth.\n\n**Fields:**\n- `mdReqID` (262): Your subscription request ID, echoed from the original request\n- `symbol` (55): Product symbol (e.g. `BTC-USD`)\n- `noMDEntries` (268): Number of price levels included\n- **MDEntry Repeating Group** (one entry per level):\n  - `mdEntryType` (269): `0` = Bid, `1` = Offer\n  - `mdEntryPx` (270): Price level\n  - `mdEntrySize` (271): Quantity available at this level\n  - `mdEntryPositionNo` (290): Position in book (`1` = best bid/ask, `2` = second-best, etc.)\n\n**Example — BTC-USD top 3 levels (pipe-delimited FIX body tags):**\n```\n35=W|262=md-req-001|55=BTC-USD|268=6|269=0|270=45100.00|271=0.5|290=1|269=0|270=45095.00|271=1.2|290=2|269=0|270=45090.00|271=2.0|290=3|269=1|270=45105.00|271=0.3|290=1|269=1|270=45110.00|271=0.8|290=2|269=1|270=45115.00|271=1.5|290=3|\n```\n","operationId":"trade.fix.marketData.marketDataSnapshot","x-fix-msg-type":"W","tags":["Market Data FIX"],"responses":{"200":{"description":"Full orderbook snapshot at requested depth.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataSnapshotFullRefresh"}}}}}}},"/fix/market-data (market data incremental)":{"get":{"x-internal":false,"summary":"Market Data Incremental Refresh (35=X)","description":"The server sends MarketDataIncrementalRefresh (`35=X`) to the client over TLS/TCP. This is not an HTTP response.\n\nSent on each orderbook update cycle (~300 ms) when prices or quantities change. Only changed\nlevels are included in the message.\n\n**Fields:**\n- `mdReqID` (262): Your subscription request ID\n- `noMDEntries` (268): Number of updates in this message\n- **MDEntry Repeating Group** (one entry per changed level):\n  - `mdUpdateAction` (279): `0` = New level, `1` = Size changed, `2` = Level removed\n  - `mdEntryType` (269): `0` = Bid, `1` = Offer\n  - `symbol` (55): Product symbol\n  - `mdEntryPx` (270): Price level\n  - `mdEntrySize` (271): New size (only for New/Changed actions; omitted for removals)\n\n**Gap Detection:** Tag 83 (RptSeq) is not present on incremental updates. Use session-level\nMsgSeqNum (tag 34) for gap detection. QuickFIX manages this automatically. On detected gap,\nresubscribe with SubscriptionRequestType=1 to receive a fresh snapshot.\n\n**Example — Bid changed, offer removed (pipe-delimited FIX body tags):**\n```\n35=X|262=md-req-001|268=2|279=1|269=0|55=BTC-USD|270=45100.00|271=0.8|279=2|269=1|55=BTC-USD|270=45105.00|\n```\n","operationId":"trade.fix.marketData.marketDataIncremental","x-fix-msg-type":"X","tags":["Market Data FIX"],"responses":{"200":{"description":"Orderbook updates for changed levels.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataIncrementalRefresh"}}}}}}},"/fix/market-data (market data reject)":{"get":{"x-internal":false,"summary":"Market Data Request Reject (35=Y)","description":"The server sends MarketDataRequestReject (`35=Y`) to the client over TLS/TCP. This is not an HTTP response.\n\nSent when a MarketDataRequest cannot be fulfilled due to invalid symbol, duplicate request ID,\nrate limits, or other constraints.\n\n**Error Codes (Tag 281):**\n- `0`: Unknown symbol. Product not available or trading halted\n- `1`: Duplicate MDReqID. This request ID is already in use; choose a unique ID\n- `2`: Insufficient Bandwidth. Too many active subscriptions or rate limit exceeded\n- `4`: Unsupported SubscriptionRequestType (263). Must be 0, 1, or 2\n- `5`: Unsupported MarketDepth (264). Must be 0–100\n- `6`: Unsupported MDUpdateType (265). Must be 0 (full) or 1 (incremental)\n- `8`: Unsupported MDEntryType. Trade data not yet supported; use only 0 (Bid) and 1 (Offer)\n- `10`: Unsupported Scope. Market data unavailable for this symbol\n\n**Fields:**\n- `mdReqID` (262): Echoed from the original request. Use this to correlate with your subscription\n- `mdReqRejReason` (281): Numeric code (see above)\n- `text` (58): Human-readable description (present when non-empty)\n","operationId":"trade.fix.marketData.marketDataReject","x-fix-msg-type":"Y","tags":["Market Data FIX"],"responses":{"200":{"description":"Rejection details for a failed market data request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketDataRequestReject"}}}}}}}},"components":{"schemas":{"ExecutionReport":{"type":"object","description":"ExecutionReport (`35=8`). Server → client. Lifecycle events for NewOrderSingle, cancels,\nfills, rejects, and OrderStatusRequest (`150=I`).\n\nCorrelate with ClOrdID (11) and OrderID (37). `ExecType=F` is used for all fills.\nUse `OrdStatus` (39) and `LeavesQty` (151) for working vs terminal state — not `150=F`\nalone. Terminal Filled (`39=2`, typically `151=0`) is usually on the following Order\nStatus report (`150=I`), not on the last fill.\n","required":["orderID","execID","execType","ordStatus","symbol","side","clOrdID","cumQty","leavesQty","avgPx","transactTime"],"properties":{"account":{"type":"string","title":"1 Account","description":"**Optional** Trading account ID (Go account ID)"},"avgPx":{"type":"string","title":"6 AvgPx","description":"**Required.** Average fill price (`0` if unfilled)."},"clOrdID":{"type":"string","title":"11 ClOrdID","description":"**Required.** Client order id. `NONE` on cancel reports (PendingCancel / Canceled) and when the order has no client id."},"cumQty":{"type":"string","title":"14 CumQty","description":"**Required.** Total quantity filled so far."},"currency":{"type":"string","title":"15 Currency","description":"**Optional.** Quantity currency for tag 38."},"execID":{"type":"string","title":"17 ExecID","description":"**Required.** Unique id for this ExecutionReport."},"lastPx":{"type":"string","title":"31 LastPx","description":"**Conditional.** This fill's price. Present **only** when ExecType = F (Trade). Omitted otherwise."},"lastQty":{"type":"string","title":"32 LastQty","description":"**Conditional.** This fill's quantity. Present **only** when ExecType = F (Trade). Omitted otherwise."},"orderID":{"type":"string","title":"37 OrderID","description":"**Required.** BitGo order UUID. `NONE` on some reject reports."},"orderQty":{"type":"string","title":"38 OrderQty","description":"**Optional.** Original order quantity echoed from the NewOrderSingle."},"ordStatus":{"type":"string","title":"39 OrdStatus","enum":["0","1","2","4","6","8","A"],"description":"**Required.** Current order state:\n`A` Pending New, `0` New, `1` Partially Filled, `2` Filled,\n`4` Canceled, `6` Pending Cancel, `8` Rejected.\n"},"ordType":{"type":"string","title":"40 OrdType","enum":["1","2","3","4"],"description":"**Optional.** Echoed from the original NewOrderSingle."},"origClOrdID":{"type":"string","title":"41 OrigClOrdID","description":"**Optional / Conditional.** Set on cancel-related ERs to the original NOS ClOrdID."},"price":{"type":"string","title":"44 Price","description":"**Optional.** Limit price echoed from the original NewOrderSingle."},"side":{"type":"string","title":"54 Side","enum":["1","2","7"],"description":"**Required.** `1` Buy, `2` Sell. `7` Undisclosed may appear on some reject reports."},"symbol":{"type":"string","title":"55 Symbol","description":"**Required.** Product echoed from the NewOrderSingle. `N/A` on some reject reports."},"text":{"type":"string","title":"58 Text","description":"**Optional / Conditional.** Human-readable detail. Present on rejects (`150=8`), on system-initiated Canceled reports (`150=4`), and on OrderStatus reports (`150=I`) describing a canceled order, carrying the client-facing cancellation reason (e.g. `Insufficient balance for reservation`). Absent for user-initiated cancels."},"timeInForce":{"type":"string","title":"59 TimeInForce","enum":["1","3","4","6"],"description":"**Optional.** Echoed from the original NewOrderSingle."},"transactTime":{"type":"string","title":"60 TransactTime","description":"**Required.** UTC business timestamp for this report."},"stopPx":{"type":"string","title":"99 StopPx","description":"**Optional.** Stop/trigger price echoed from the original NewOrderSingle."},"ordRejReason":{"type":"integer","title":"103 OrdRejReason","enum":[1,2,3,6,15,99],"description":"**Conditional.** Present only when ExecType = 8 (Rejected).\n`1` Unknown symbol, `2` Market unavailable, `3` OrderExceedsLimit,\n`6` Duplicate ClOrdID, `15` UnknownAccount, `99` Other (see Text).\n"},"execType":{"type":"string","title":"150 ExecType","enum":["0","4","6","8","A","F","I"],"description":"**Required.** Event type:\n`A` PendingNew, `0` New, `F` Trade (partial or full), `6` PendingCancel,\n`4` Canceled, `8` Rejected, `I` Order Status (response to `35=H`, and terminal\nstatus summary after a full fill).\n"},"leavesQty":{"type":"string","title":"151 LeavesQty","description":"**Required.** Quantity still open. Use together with `OrdStatus` (39) for\nworking vs terminal state. On terminal Canceled reports (`150=4` / `39=4`)\nthis stays at the open quantity at cancel time; it is **not** reset to `0`\n(`39=4` is canceled even when `151` > `0`). On fills, `151=0` with `39=1` is\nnot yet terminal Filled — wait for `39=2` (typically on `150=I`).\n"},"effectiveTime":{"type":"string","title":"168 EffectiveTime","description":"**Optional.** Scheduled activation time echoed from NOS."},"grossTradeAmt":{"type":"string","title":"381 GrossTradeAmt","description":"**Optional.** Cumulative filled quote quantity (equivalent to REST `filledQuoteQuantity`)."},"targetStrategy":{"type":"string","title":"847 TargetStrategy","enum":["T","S"],"description":"**Optional.** Algo strategy echoed from the original order (`T` TWAP, `S` SteadyPace)."},"noStrategyParameters":{"type":"integer","title":"957 NoStrategyParameters","description":"**Optional.** Strategy param group count echoed from NOS for algo orders."},"strategyParameterName":{"type":"string","title":"958 StrategyParameterName","description":"**Optional.** Parameter name within group 957."},"strategyParameterType":{"type":"string","title":"959 StrategyParameterType","enum":["1","6","14"],"description":"**Optional.** Populated by the server on echoed strategy parameters: `1` = Int, `6` = Float, `14` = String, based on the parameter's inferred type."},"strategyParameterValue":{"type":"string","title":"960 StrategyParameterValue","description":"**Optional.** Parameter value within group 957."},"fundingType":{"type":"string","title":"5001 FundingType","enum":["1","2"],"description":"**Optional.** `1` Funded, `2` Margin. Echoed from the original order."}}},"Heartbeat":{"type":"object","description":"Heartbeat (`35=0`) body fields.","properties":{"testReqID":{"type":"string","title":"112 TestReqID","description":"**Conditional.** Required when this Heartbeat is a response to a TestRequest (`35=1`); otherwise omit."}}},"LogonMessage":{"type":"object","description":"Logon (`35=A`) body fields. Standard header/trailer are also required on every message.\nAuthenticate with Password (554); there is no Username (553). SenderCompID (49) identifies the account.\n","required":["password","encryptMethod","heartBtInt"],"properties":{"password":{"type":"string","title":"554 Password","description":"**Required.** BitGo access token."},"encryptMethod":{"type":"string","title":"98 EncryptMethod","enum":["0"],"example":"0","description":"**Required.** Must be `0` (None). TLS encrypts the transport."},"heartBtInt":{"type":"integer","title":"108 HeartBtInt","enum":[30],"example":30,"description":"**Required.** Heartbeat interval in seconds. Must be `30` to match the server."},"resetSeqNumFlag":{"type":"string","title":"141 ResetSeqNumFlag","enum":["Y","N"],"example":"Y","description":"**Optional.** Must be `Y` when sent. Sequence numbers reset to 1 on every\nconnection (stateless session model) regardless, as the server is configured\nwith ResetOnLogon=Y.\n"}}},"Logout":{"type":"object","description":"Logout (`35=5`) body fields.","properties":{"text":{"type":"string","title":"58 Text","description":"**Optional** on client-initiated Logout. On server-initiated Logout, carries the reason (e.g. `session expired`, `access token revoked`, `server draining, please reconnect`, or Logon reject text)."}}},"MarketDataEntry":{"type":"object","description":"Single bid/offer level in a snapshot (MDEntries repeating group).","required":["mdEntryType","mdEntryPx","mdEntrySize","mdEntryPositionNo"],"properties":{"mdEntryType":{"type":"string","title":"269 MDEntryType","enum":["0","1"],"description":"**Required.** `0` Bid, `1` Offer."},"mdEntryPx":{"type":"string","title":"270 MDEntryPx","description":"**Required.** Price level.","example":"45100.00"},"mdEntrySize":{"type":"string","title":"271 MDEntrySize","description":"**Required.** Quantity at this level.","example":"0.5"},"mdEntryPositionNo":{"type":"integer","title":"290 MDEntryPositionNo","description":"**Required.** Position in book (`1` = best).","example":1}}},"MarketDataIncrementalRefresh":{"type":"object","description":"MarketDataIncrementalRefresh (`35=X`). Server → client (~300 ms cycle). Changed levels only.\nTag 83 (RptSeq) is **not** present. Use session MsgSeqNum (34) for gap detection; on gap,\nresubscribe with `263=1`.\n","required":["mdReqID","noMDEntries","mdUpdates"],"properties":{"mdReqID":{"type":"string","title":"262 MDReqID","description":"**Required.** Subscription request ID."},"noMDEntries":{"type":"integer","title":"268 NoMDEntries","description":"**Required.** Number of updates in this message."},"mdUpdates":{"type":"array","title":"MDEntry Updates","items":{"$ref":"#/components/schemas/MarketDataIncrementalUpdate"}}}},"MarketDataIncrementalUpdate":{"type":"object","description":"Single level change in an incremental refresh.","required":["mdUpdateAction","mdEntryType","symbol","mdEntryPx"],"properties":{"mdUpdateAction":{"type":"string","title":"279 MDUpdateAction","enum":["0","1","2"],"description":"**Required.** `0` New, `1` Change, `2` Delete."},"mdEntryType":{"type":"string","title":"269 MDEntryType","enum":["0","1"],"description":"**Required.** `0` Bid, `1` Offer."},"symbol":{"type":"string","title":"55 Symbol","description":"**Required.** Product symbol."},"mdEntryPx":{"type":"string","title":"270 MDEntryPx","description":"**Required.** Price level."},"mdEntrySize":{"type":"string","title":"271 MDEntrySize","description":"**Conditional.** New size for New/Change; omitted on Delete (`279=2`)."}}},"MarketDataRequest":{"type":"object","description":"MarketDataRequest (`35=V`) on the **BITGO-MD** session. Aggregated Level 2 orderbook.\n","required":["mdReqID","subscriptionRequestType","marketDepth","noMDEntryTypes","mdEntryType","noRelatedSym","symbol"],"properties":{"mdReqID":{"type":"string","title":"262 MDReqID","description":"**Required.** Client-assigned request ID; must be unique per active subscription.","example":"md-req-001"},"subscriptionRequestType":{"type":"string","title":"263 SubscriptionRequestType","enum":["0","1","2"],"description":"**Required.** `0` Snapshot only, `1` Snapshot + Subscribe, `2` Unsubscribe."},"marketDepth":{"type":"integer","title":"264 MarketDepth","minimum":0,"maximum":100,"example":10,"description":"**Required.** `0` = full book (up to 100 levels/side); `1`–`100` = top N. Values ≥ 101 → reject `281=5`."},"mdUpdateType":{"type":"string","title":"265 MDUpdateType","enum":["0","1"],"description":"**Optional.** Defaults to `0` (Full Refresh) if omitted; set `265=1` explicitly for\nincremental updates on a live subscription.\n`0` = Full Refresh, `1` = Incremental updates.\n"},"noMDEntryTypes":{"type":"integer","title":"267 NoMDEntryTypes","description":"**Required.** Number of MDEntryType (269) values that follow. Typically `2` (Bid + Offer).","example":2},"mdEntryType":{"type":"string","title":"269 MDEntryType","enum":["0","1"],"description":"**Required** (repeating). `0` = Bid, `1` = Offer.\nTrade (`2`) is not supported → reject `281=8`.\n"},"noRelatedSym":{"type":"integer","title":"146 NoRelatedSym","description":"**Required.** Number of symbols in this request. Max 20 symbols per request.","example":1},"symbol":{"type":"string","title":"55 Symbol","example":"BTC-USD","description":"**Required** (repeating under 146). Product symbol.\nLimits: 50 subscriptions/session; 100 symbols/enterprise across sessions.\n"}}},"MarketDataRequestReject":{"type":"object","description":"MarketDataRequestReject (`35=Y`). Server → client when MarketDataRequest fails.","required":["mdReqID","mdReqRejReason"],"properties":{"mdReqID":{"type":"string","title":"262 MDReqID","description":"**Required.** Echoed from the original request."},"mdReqRejReason":{"type":"integer","title":"281 MDReqRejReason","enum":[0,1,2,4,5,6,8,10],"description":"**Required.**\n`0` Unknown symbol, `1` Duplicate MDReqID, `2` Insufficient Bandwidth,\n`4` Unsupported SubscriptionRequestType, `5` Unsupported MarketDepth,\n`6` Unsupported MDUpdateType, `8` Unsupported MDEntryType,\n`10` Unsupported Scope.\n"},"text":{"type":"string","title":"58 Text","description":"**Optional.** Human-readable reason when non-empty."}}},"MarketDataSnapshotFullRefresh":{"type":"object","description":"MarketDataSnapshotFullRefresh (`35=W`). Server → client. Sent on subscribe and snapshot-only.\n","required":["mdReqID","symbol","noMDEntries","mdEntries"],"properties":{"mdReqID":{"type":"string","title":"262 MDReqID","description":"**Required.** Echoed subscription request ID."},"symbol":{"type":"string","title":"55 Symbol","description":"**Required.** Product symbol."},"noMDEntries":{"type":"integer","title":"268 NoMDEntries","description":"**Required.** Number of entries in this snapshot."},"mdEntries":{"type":"array","title":"MDEntry Repeating Group (268)","description":"Bid and offer levels up to requested depth.","items":{"$ref":"#/components/schemas/MarketDataEntry"}}}},"NewOrderSingle":{"type":"object","description":"NewOrderSingle (`35=D`) body fields.\nField descriptions mark Required / Optional / Conditional.\n","required":["clOrdID","symbol","side","orderQty","currency","ordType","transactTime"],"properties":{"account":{"type":"string","title":"1 Account","description":"**Optional.** Per-message trading account. When present, validated against the session\nGo Account ID (from SenderCompID). Mismatch → ExecutionReport reject.\n"},"clOrdID":{"type":"string","title":"11 ClOrdID","description":"**Required.** Client-assigned order ID (≤ 256 chars; UUID recommended). Duplicate → reject `103=6`."},"symbol":{"type":"string","title":"55 Symbol","example":"TBTC-TUSD*","description":"**Required.** Trading pair / product (e.g. `TBTC-TUSD*`, `ETH-USD*`)."},"side":{"type":"string","title":"54 Side","enum":["1","2"],"description":"**Required.** `1` = Buy, `2` = Sell."},"orderQty":{"type":"string","title":"38 OrderQty","description":"**Required.** Order quantity in the currency of tag 15. Must be > 0.\nPrecision follows the product Base Increment / Quote Increment for that currency.\n\n| QuantityCurrency (15) | Side | Meaning |\n|---|---|---|\n| Base (e.g. BTC) | Buy | Buy N base units |\n| Base (e.g. BTC) | Sell | Sell N base units |\n| Quote (e.g. USD) | Buy | Buy N quote notional of base |\n| Quote (e.g. USD) | Sell | Sell base for N quote notional |\n\nSize orders with `OrderQty` (38) and `Currency` (15).\n\n**Increments are precision constraints, not minimums.** `baseIncrement` and\n`quoteIncrement` define the permitted quantity precision (step size) for the\ndenomination selected by `Currency` (15). Do not divide or otherwise combine\nincrements to calculate a minimum order quantity.\n\n**Minimum order size** comes from the Products REST response fields\n`baseMinSize` and `quoteMinSize`, which are independent minimums in their own\ncurrencies: see [List Products](https://developers.bitgo.com/reference/tradeproducts).\nThe FIX gateway does not provide product-rule discovery (no SecurityList or\nSecurityDefinition messages); fetch minimums and increments from the\nProducts endpoint.\n\nWhen `baseMinSize` is empty but `quoteMinSize` is set, a base-denominated\norder must still meet the quote-currency minimum after its value is calculated\nusing the validation price, so the effective base minimum varies with price.\n(The Products REST response always includes both fields; unset minimums are\nreturned as empty strings, not omitted.)\nFor market and limit orders, both configured minimums are checked regardless of\nthe quantity currency: a base-denominated order must still meet `quoteMinSize`,\nand a quote-denominated order must still meet `baseMinSize`.\n\n**Validation price:** passive limit orders are validated against the submitted\nlimit price; market and marketable-limit orders (limit price would execute\nimmediately) are validated against an indicative market price observed at\nvalidation time. The validation price may differ from the price at which the\norder ultimately executes.\n\nTWAP and SteadyPace orders are additionally subject to strategy-specific sizing\nrules, such as the `SubOrderSize` minimum under `TargetStrategy` (847); product\nminimums alone do not describe the sizing rules for every order type.\n\nExample (precision is not a minimum): a product with `baseIncrement` `0.0001`,\nan empty `baseMinSize`, and `quoteMinSize` `20.00` does not accept a minimum\norder of\n`0.0001` BTC. `0.0001` is only the allowed quantity precision. If BTC is priced\nat $40,000, a base-denominated order must be worth at least $20, i.e. at least\n`0.0005` BTC (a valid increment multiple). On rejection, `Text` (58) states the\nminimum in the currency whose limit was not met (the quote currency here), e.g.\n`Amount must be at least 20 USD.`\n"},"currency":{"type":"string","title":"15 Currency (QuantityCurrency)","example":"TBTC","description":"**Required.** Currency of `OrderQty` (38). Must be the product base or quote currency;\ndetermines base-unit vs quote-notional sizing.\nBoth buy and sell are supported for base- and quote-denominated sizes.\nWhen absent or empty, defaults to the product base currency.\nMust match against currencies in [List Currencies](https://developers.bitgo.com/reference/tradecurrencies/)\nand be consistent with Product (55).\nFetch product minimums and quantity precision from\n[List Products](https://developers.bitgo.com/reference/tradeproducts).\n"},"ordType":{"type":"string","title":"40 OrdType","enum":["1","2","3","4"],"example":"2","description":"**Required.**\n`1` = Market, `2` = Limit, `3` = Stop (market when triggered), `4` = Stop Limit.\n\nWhen TargetStrategy (847) is absent: `1`→Sweep, `2`→Limit, `3`/`4`→Stop.\nTag 847 is **not allowed** with `40=3` or `40=4`.\n"},"transactTime":{"type":"string","title":"60 TransactTime","example":"20260528-10:34:21.000","description":"**Required.** Client order-creation time (UTC). Format `YYYYMMDD-HH:MM:SS[.sss[sss]]`."},"price":{"type":"string","title":"44 Price","example":"83220.0","description":"**Conditional.**\n- **Required** when OrdType = Limit (`40=2`) (strategy Limit).\n- **Optional** for TWAP / SteadyPace. When present, acts as a limit cap.\n- **Optional** for Stop (`40=3`/`40=4`): present → stop-limit; absent → stop-market.\n  Send Price with `40=4` (Stop Limit).\n\nMust be > 0 when present. Precision: product QuoteDisplayPrecision.\n"},"stopPx":{"type":"string","title":"99 StopPx","description":"**Conditional.** Trigger price.\n**Required** when OrdType is Stop or Stop Limit (`40=3` or `40=4`).\nUse only with Stop / Stop Limit orders.\n"},"timeInForce":{"type":"string","title":"59 TimeInForce","enum":["1","3","4","6"],"description":"**Optional.**\n`1` = GTC (default for Limit and Stop when omitted).\n`3` = IOC (Limit and Market orders only).\n`4` = FOK (Fill or Kill).\n`6` = GTD (requires ExpireTime 126).\n"},"expireTime":{"type":"string","title":"126 ExpireTime","description":"**Conditional.** Expiration timestamp (UTC).\n**Required** when TimeInForce = GTD (`59=6`).\nMust not be set unless `59=6`.\n"},"effectiveTime":{"type":"string","title":"168 EffectiveTime","description":"**Optional.** Scheduled activation time (UTC). Maps to REST `ScheduledDate`."},"targetStrategy":{"type":"string","title":"847 TargetStrategy","enum":["1","2","T","S"],"description":"**Optional.** Execution strategy.\n`1` = Market/Sweep (**requires** `40=1`), `2` = Limit (**requires** `40=2`),\n`T` = TWAP (`40=1` or `40=2`), `S` = SteadyPace (`40=1` or `40=2`).\nWhen absent, derived from OrdType. **Not allowed** with `40=3` or `40=4`.\n"},"noStrategyParameters":{"type":"integer","title":"957 NoStrategyParameters","description":"**Conditional.** Count of strategy-parameter entries (repeating group with 958/959/960).\nRequired for TWAP (`847=T`) and SteadyPace (`847=S`).\nTag 959 is optional between each 958/960 pair.\n"},"strategyParameterName":{"type":"string","title":"958 StrategyParameterName","description":"**Conditional** (inside group 957). Parameter name.\n\n**TWAP (`847=T`):**\n| Name | Required | Notes |\n|---|---|---|\n| `Duration` | **Yes** | Minutes (integer ≥ 1) |\n| `IsTimeSliced` | No | `true` / `false` (default false) |\n| `Interval` | **Conditional** | Minutes; **required when** `IsTimeSliced=true`; Duration must be divisible by Interval |\n| `BoundsControl` | No | `narrow` / `standard` / `wide` (**lowercase**); used when not time-sliced |\n\n**SteadyPace (`847=S`):**\n| Name | Required | Notes |\n|---|---|---|\n| `Interval` | **Yes** | Integer > 0 |\n| `SubOrderSize` | **Yes** | Decimal; must be < total order qty/funds and at least the product minimum sub-order size (dynamic; the reject text states the current minimum) |\n| `IntervalUnit` | No | `second` / `minute` / `hour` (**lowercase**; default `minute`) |\n| `Variance` | No | Decimal 0.0–1.0 |\n\n**Limit (`847=2` or derived from `40=2`):**\n| Name | Required | Notes |\n|---|---|---|\n| `Duration` | No | Minutes (integer ≥ 1); creates a limit-with-duration order |\n"},"strategyParameterType":{"type":"string","title":"959 StrategyParameterType","enum":["1","6","14"],"description":"**Optional.** Accepted for FIX compliance but ignored by the server on inbound orders;\nparameter types are inferred from the parameter name (958). Any listed value may be sent\nor the tag omitted entirely.\n"},"strategyParameterValue":{"type":"string","title":"960 StrategyParameterValue","description":"**Conditional** (with 958). Parameter value. `BoundsControl` and `IntervalUnit` must be **lowercase** on the wire."},"fundingType":{"type":"string","title":"5001 FundingType","enum":["1","2"],"description":"**Optional.** BitGo custom tag. `1` = Funded (default when absent), `2` = Margin."}}},"OrderCancelReject":{"type":"object","description":"OrderCancelReject (`35=9`). Server → client when OrderCancelRequest cannot be fulfilled.\n`CxlRejResponseTo` (434) is always `1` (OrderCancelRequest).\n","required":["orderID","ordStatus","text","transactTime","cxlRejReason","cxlRejResponseTo"],"properties":{"account":{"type":"string","title":"1 Account","description":"**Optional.** Echoed when available (inbound cancel Account or session Go Account ID).\nOmitted when empty.\n"},"orderID":{"type":"string","title":"37 OrderID","description":"**Required.** Echoed from the cancel request, or `NONE` when absent."},"clOrdID":{"type":"string","title":"11 ClOrdID","description":"**Optional.** Echoed from the cancel request."},"origClOrdID":{"type":"string","title":"41 OrigClOrdID","description":"**Optional.** Echoed from the cancel request (`NONE` when empty)."},"ordStatus":{"type":"string","title":"39 OrdStatus","enum":["0","1","2","4","6","8","A"],"description":"**Required.** Current order status. Often `8` on rejects; real status when `102=0` (too late)."},"text":{"type":"string","title":"58 Text","description":"**Required.** Human-readable rejection reason."},"transactTime":{"type":"string","title":"60 TransactTime","description":"**Required.** Echoed from the cancel request when present."},"cxlRejReason":{"type":"integer","title":"102 CxlRejReason","enum":[0,1,99],"description":"**Required.**\n`0` Too late to cancel (already filled/canceled/pending cancel).\n`1` Unknown order.\n`99` Other (system error, account mismatch, non-cancelable state; see Text).\n"},"cxlRejResponseTo":{"type":"string","title":"434 CxlRejResponseTo","enum":["1"],"description":"**Required.** Always `1` (OrderCancelRequest)."}}},"OrderCancelRequest":{"type":"object","description":"OrderCancelRequest (`35=F`) body fields.\nAt least one of OrderID (37) or OrigClOrdID (41) is required to identify the order; tag 37 takes precedence when both are present.\nTransactTime (60) is the only unconditionally required field.\n","required":["transactTime"],"properties":{"clOrdID":{"type":"string","title":"11 ClOrdID","description":"**Optional.** Unique ID for this cancel request. This ID is not echoed back in the cancel ExecutionReports."},"origClOrdID":{"type":"string","title":"41 OrigClOrdID","description":"**Conditional.** ClOrdID of the order to cancel; must match the ClOrdID sent in the NewOrderSingle. Required if OrderID (37) is absent."},"orderID":{"type":"string","title":"37 OrderID","description":"**Conditional.** BitGo order UUID from ExecutionReport. When present, takes precedence over OrigClOrdID (41) for order resolution."},"transactTime":{"type":"string","title":"60 TransactTime","example":"20260528-10:34:21.000","description":"**Required.** UTC timestamp. Format `YYYYMMDD-HH:MM:SS[.sss]`."},"account":{"type":"string","title":"1 Account","description":"**Optional.** Must match the session account. Rejected if present and mismatched."}}},"OrderStatusRequest":{"description":"OrderStatusRequest (`35=H`) body fields.\nAt least one of OrderID (37) or ClOrdID (11) is required; tag 37 takes precedence when both are present.\n","allOf":[{"type":"object","properties":{"clOrdID":{"type":"string","title":"11 ClOrdID","description":"**Conditional.** Client order id of the order whose status is being requested. At least one of 37 or 11 required."},"orderID":{"type":"string","title":"37 OrderID","description":"**Conditional.** BitGo order UUID from the ExecutionReport reports. At least one of 37 or 11 required; takes precedence when both are present."}}},{"anyOf":[{"type":"object","properties":{"orderID":{"type":"string"}},"required":["orderID"]},{"type":"object","properties":{"clOrdID":{"type":"string"}},"required":["clOrdID"]}]}]},"SessionReject":{"type":"object","description":"Session Reject (`35=3`). Server → client. Session-level protocol error (malformed message,\nmissing required tag, invalid MsgType). Distinct from business rejects (`35=8` / `35=9`).\n","required":["refSeqNum","refMsgType","sessionRejectReason"],"properties":{"refSeqNum":{"type":"integer","title":"45 RefSeqNum","description":"**Required.** MsgSeqNum (34) of the rejected message."},"refTagID":{"type":"integer","title":"371 RefTagID","description":"**Optional.** Tag number of the offending field, when known."},"refMsgType":{"type":"string","title":"372 RefMsgType","description":"**Required.** MsgType (35) of the rejected message."},"sessionRejectReason":{"type":"integer","title":"373 SessionRejectReason","enum":[0,1,5,6,11,99],"description":"**Required.** Session-level reject reason:\n`0` Invalid tag number, `1` Required tag missing, `5` ValueIncorrect,\n`6` IncorrectFormat, `11` InvalidMsgType, `99` Other.\n"},"text":{"type":"string","title":"58 Text","description":"**Optional.** Human-readable rejection reason."}}},"StandardHeader":{"type":"object","description":"The Standard Header must be present at the start of every FIX message in both directions.\n","required":["beginString","bodyLength","msgType","msgSeqNum","sendingTime","senderCompID","targetCompID"],"properties":{"beginString":{"type":"string","title":"8 BeginString","description":"**Required.** Must be `FIX.4.4`. Must be the first field in the message.","enum":["FIX.4.4"],"example":"FIX.4.4"},"bodyLength":{"type":"integer","title":"9 BodyLength","description":"**Required.** Message body length in bytes. Must be the second field. Computed by the FIX engine."},"msgType":{"type":"string","title":"35 MsgType","description":"**Required.** Must be the third field. Supported BitGo message types:\n\n| MsgType | Name | Direction |\n|---|---|---|\n| `A` | Logon | Both |\n| `0` | Heartbeat | Both |\n| `1` | TestRequest | Both |\n| `3` | Session Reject | Server → Client |\n| `5` | Logout | Both |\n| `D` | New Order Single | Client → Server |\n| `F` | Order Cancel Request | Client → Server |\n| `H` | Order Status Request | Client → Server |\n| `8` | ExecutionReport | Server → Client |\n| `9` | OrderCancelReject | Server → Client |\n| `V` | Market Data Request | Client → Server |\n| `W` | MarketDataSnapshotFullRefresh | Server → Client |\n| `X` | MarketDataIncrementalRefresh | Server → Client |\n| `Y` | MarketDataRequestReject | Server → Client |\n\nUnsupported application MsgTypes (e.g. CancelReplace `G`) are rejected with Session Reject\n(`35=3`, `373=11`). ResendRequest (`35=2`) is not supported.\n"},"msgSeqNum":{"type":"integer","title":"34 MsgSeqNum","description":"**Required.** Starts at `1` at session start; increments by 1. Sequence numbers reset on every connection under the stateless model (`141=Y`).","example":1},"sendingTime":{"type":"string","title":"52 SendingTime","description":"**Required.** UTC timestamp when the message is sent. Format `YYYYMMDD-HH:MM:SS[.sss[sss]]` (seconds, ms, or µs).","example":"20260528-10:34:21.000"},"senderCompID":{"type":"string","title":"49 SenderCompID","description":"**Required.** Client → server: your 32-character hex Go Account ID. Server → client: `BITGO` or `BITGO-MD`.","example":"0123456789abcdef0123456789abcdef"},"targetCompID":{"type":"string","title":"56 TargetCompID","description":"**Required.** Client → server: `BITGO` (order entry) or `BITGO-MD` (market data). Server → client: your Account ID.","enum":["BITGO","BITGO-MD"]}}},"StandardTrailer":{"type":"object","description":"The Standard Trailer must be present at the end of every FIX message.","required":["checkSum"],"properties":{"checkSum":{"type":"string","title":"10 CheckSum","description":"**Required.** Always the last field. Three-digit checksum (sum of ASCII values of all preceding characters modulo 256). Computed by the FIX engine."}}},"TestRequest":{"type":"object","description":"TestRequest (`35=1`) body fields.","required":["testReqID"],"properties":{"testReqID":{"type":"string","title":"112 TestReqID","description":"**Required.** Arbitrary identifier echoed back on the Heartbeat response."}}}}}}