Trading

Learn how to place, modify, and cancel account-scoped orders with idempotency.

Once the user grants trading access for a financial account, you can place, modify, and cancel orders through Finatic account-scoped routes. The accountId path parameter is the financial account ID returned by account APIs.

Requirements

All trading operations require:

  • An active account grant with canTrade: true.
  • A valid financial accountId.
  • Broker-specific order fields (see order schemas).
  • An idempotency key for write commands.

Important: Trading operations fail with an access error when the user only granted read permissions. Send the user back through Connect and request trading access for that account.

Typical workflow

  1. Confirm the selected account grant has canTrade: true.
  2. Fetch broker order field schemas for the account (GET /api/v1/accounts/{accountId}/order-schemas?action=place).
  3. Submit an order with an idempotency key and { order: { ... } } body envelope.
  4. Read the command result (accepted, embedded order snapshot).
  5. Track order status with finatic.v1.listOrders({ accountId }) or webhooks.
  6. Read fills and events from /api/v1/accounts/{accountId}/orders/{orderId}/fills and /events.
  7. Modify or cancel active orders with the same account-scoped route family.

Request and response shape

Write commands use an envelope body:

1{ 2"broker": "robinhood", 3"order": { 4"orderType": "market", 5"assetType": "equity", 6"action": "buy", 7"timeInForce": "day", 8"symbol": "AAPL", 9"orderQty": 1 10} 11} 12

broker is optional. When provided, it must match the account grant's broker.

Responses return FDXBrokerOrderCommandResult:

1{ 2"action": "PLACE", 3"accepted": true, 4"executionStrategy": "CANCEL_REPLACE", 5"order": { 6"orderId": "ord_123", 7"status": "PENDING", 8"legs": [] 9}, 10"clientOrderId": "partner-order-123", 11"supersededOrderId": null, 12"message": null 13} 14

executionStrategy tells you how Finatic executed the command:

ValueWhen
CANCEL_REPLACEDefault for REST brokers — modify is implemented as cancel + replace when needed
NATIVE_MODIFYBroker-native modify (e.g. eToro position SL/TP via modifyTarget=position_sl_tp)
ASYNC_COMMANDMT4/MT5 — command queued to the customer EA; Finatic waits for an acknowledgement window

For ASYNC_COMMAND, the embedded order may include the EA ticket as brokerOrderId once acknowledged. On timeout or rejection, the API returns MT_COMMAND_TIMEOUT or MT_COMMAND_REJECTED.

The embedded order uses the same shape as GET /api/v1/accounts/{accountId}/orders. Order lifecycle webhooks fire from persisted integration.orders updates — you do not need to poll after a successful write.

Order field schemas

Discover broker-specific fields before building your UI or validation:

1const schema = await finatic.v1.getAccountOrderSchema({ 2accountId: 'account_123', 3action: 'place', 4}); 5

Supported action values: place, modify, cancel.

The schema response includes supportedOrderTypesByAssetClass — a map of asset class to allowed orderType values for that broker account. Use this at runtime instead of hard-coding broker matrices.

1{ 2"supportedOrderTypesByAssetClass": { 3"equity": ["market", "limit", "stop", "stop_limit", "trailing_stop"], 4"option": ["market", "limit"] 5} 6} 7

Per-broker trading notes

BrokerEntry order typesModify behavior
Alpaca, Robinhood, Webull, TradeStation, Tastytrade, NinjaTrader, Trading 212See supportedOrderTypesByAssetClass
Cancel-replace (CANCEL_REPLACE)
eToromarket, limit per asset classPosition SL/TP: set modifyTarget to position_sl_tp with positionId
(NATIVE_MODIFY). Other modifies use cancel-replace.
MT4 / MT5market, limit, stop onlyAsync EA commands (ASYNC_COMMAND); requires a registered connector

eToro place payloads use instrumentId and amount/units rather than symbol/orderQty. Fetch the place schema for field names before building your form.

MT brokers require FinaticConnect EA onboarding. Commands are not synchronous — plan for the acknowledgement window and handle MT_COMMAND_TIMEOUT / MT_COMMAND_REJECTED explicitly.

Place order

Modify order

Pass the financial accountId, the order ID, an idempotency key, and only the fields you want to change inside order:

For eToro position stop-loss / take-profit updates, include broker-specific modify fields inside order:

1await finatic.v1.modifyAccountOrder({ 2accountId: 'account_123', 3orderId: 'position_456', 4idempotencyKey: 'etoro-sl-tp-1', 5body: { 6order: { 7modifyTarget: 'position_sl_tp', 8positionId: 'position_456', 9stopLossRate: 180.5, 10takeProfitRate: 195.0, 11}, 12}, 13}); 14

When Finatic uses native modify, the command result includes executionStrategy: "NATIVE_MODIFY". Cancel-replace modifies return supersededOrderId when the prior order row was replaced.

Cancel order

Order tracking

Use account-scoped reads after write commands:

1const orders = await finatic.v1.listOrders({ 2accountId: 'account_123', 3limit: 50, 4}); 5 6const fills = await finatic.v1.getAccountOrderFills({ 7accountId: 'account_123', 8orderId: 'order_123', 9}); 10

Error handling

Common trading failures:

  • Missing trading permission: The account grant does not have canTrade: true.
  • Invalid idempotency key: Reuse only when retrying the exact same command.
  • Broker rejection: Broker-specific rejection context is returned in error details.
  • Market restrictions: The broker rejected the order because the market or asset is not currently tradable.

Always log traceId with your own order ID and idempotency key.

Next steps

  1. Getting Data - Read account orders, fills, and events.
  2. Webhooks - Subscribe to order lifecycle events.
  3. Error Handling - Handle domain errors and retries.