VALIDATION_ERROR | 400 | Request body failed validation |
SIGNAL_REJECTED | 400 | Signal rejected (duplicate sourceId, etc.) |
NOT_FOUND | 404 | Not found, or no access. POST /api/v1/signals returns it when the account or strategy is missing, deleted, or not yours. POST /api/v1/orders returns it with "Account not found or access denied" when the account or its broker is deleted, and with "Strategy not found" when the strategy is deleted. A missing or not-owned account on POST /api/v1/orders returns a bare 404 with no code. |
ACCOUNT_INACTIVE | 400 | Returned by POST /api/v1/orders when the account is inactive. UTM does not place orders on it. Applies to every order, including a close. Nothing is placed. |
STRATEGY_INACTIVE | 400 | Returned by POST /api/v1/orders and POST /api/v1/signals when the strategy is inactive. On POST /api/v1/orders it applies to every order on that strategy, including a close. Nothing is placed. |
INSUFFICIENT_FUNDS | 400 | Account has insufficient buying power |
MARKET_CLOSED | 400 | Market is closed for this symbol |
SERVICE_UNAVAILABLE | 503 | A backing service the signal pipeline depends on is disabled or unreachable, for example the scheduler queue for a scheduled signal. |
DUPLICATE_INTENT | 409 | A same-direction live signal already exists for this (accountId, strategyId, symbol, action). Response details.conflictingSignalId carries the id. |
OPPOSING_POSITION_OPEN | 409 | The request would open the opposing side of an existing non-terminal trade for the same (account, symbol) on a netting broker (Alpaca, TradeStation). Response details.conflictingTradeId carries the existing trade id. Same-side stacking is allowed; opposite-side is not, because netting brokers cannot represent both sides at once. Close the conflicting trade to flat first, or route the strategy to a different account. |
SIGNAL_ALREADY_TRANSMITTED | 409 | Returned by DELETE /api/v1/signals/:id when the signal has already been sent to the broker, so it can no longer be cancelled. Response details.orderIds lists every order linked to the signal, and may be empty. Manage the order in the UTM app. The batch cancel returns the same code and orderIds on that signal's item in results. |
SIGNAL_PROCESSING | 409 | Returned by DELETE /api/v1/signals/:id when the signal is being sent to the broker right now. It carries no order ids. Check the signal again shortly, then manage its order in the UTM app. A retried cancel is refused again. The batch cancel returns the same code on that signal's item in results. |
RECONCILIATION_SYNTHETIC_CONFLICT | 409 | Returned by POST /api/v1/reconciliation/link, /unlink, /link-order, /unlink-order, and the POST /api/v1/reconciliation/repair/{tradeId}/* endpoints when the target trade still holds a synthetic (estimate) execution covering the same shares as the fill(s) or order being applied. Recalculating with both present would double-count the position and push it above the broker's reported quantity. Nothing is written. Response details carries accountId, symbol, side, brokerQuantity, utmOpenSum, exceedsBy, and conflictingTradeIds (sorted by openQuantity descending). Remove the synthetic execution first, then retry. |
RECONCILIATION_OVER_EXPOSURE | 409 | Returned by the same endpoints as RECONCILIATION_SYNTHETIC_CONFLICT when applying the recalculated trade aggregates would push UTM's open quantity for the trade's (account, symbol, side) above the broker's gross open quantity on that side, and no synthetic execution explains it. The write is refused; no partial state is committed. Response details carries the same fields as above. |