Skip to main content
In the sandbox environment, order execution is deterministic. You exercise specific outcomes (full fill, unfilled cancel, or partial fill) by placing orders with particular field values. We ship a fixed set of scenarios; you cannot add or change them. Testing execution is enabled on our side for the sandbox environment.

How scenarios are selected

When we route your order for execution, we match it against a predefined list. The first scenario whose conditions all match wins. If nothing matches, you get the default full fill. Matchers use the same fields you send when placing an order:
  • Buy orders: set cash_amount to the exact string shown below.
  • Sell orders: set quantity to the exact string shown below (and do not set cash_amount).
  • Everything else: default full fill.
Trigger values must match exactly. Use "5001", not 5001 or "5001.00". A buy with cash_amount of "5001.00" will not hit the cancel scenario; it falls through to the default full fill. The same applies to sell quantity values (for example "20", not 20 or "20.00").

Scenario reference

ScenarioHow to triggerTerminal statusWebhooks
Unfilled cancelBuy, cash_amount: "5001"cancelledorder.placedorder.executingorder.cancelled
Partial fill (40%, buy)Buy, cash_amount: "5002"filledorder.placedorder.executingtrade.executedorder.filled
Full fill (buy)Buy, cash_amount: "5003"filledorder.placedorder.executingtrade.executedorder.filled
Full fill (sell)Sell, quantity of "12" or less, no cash_amountfilledorder.placedorder.executingtrade.executedorder.filled
Partial fill (25%, sell)Sell, quantity: "20", no cash_amountfilledorder.placedorder.executingtrade.executedorder.filled
Default full fillAny other valid orderfilledorder.placedorder.executingtrade.executedorder.filled
Some orders pass through pending before executing; many skip pending entirely. See the order lifecycle for status definitions and the full webhook list.

Partial fills

Partial scenarios are easy to misread. The order ends as filled, not cancelled: we execute part of the order, then cancel what is left. You get trade.executed, then order.filled (not order.cancelled). Use Retrieve order or the trade resource to check traded_quantity and related fields.
TriggerFill %What to expect
Buy, cash_amount: "5002"40%Roughly 40% of the order fills; exact trade quantity and notional depend on the instrument and your order
Sell, quantity: "20"25%Trade quantity of 5, then order.filled
The same triggers work for currency pairs. Statuses and webhooks match the table above; trade amounts follow your FX quote rather than the sell example.

Examples

Unfilled cancel

import requests

response = requests.post(
    "https://api.engine.usesophic.com/accounts/{account_id}/orders",
    headers={
        "Authorization": "Bearer YOUR_ACCESS_TOKEN",
        "Content-Type": "application/json",
    },
    json={
        "instrument": "ins_xyz789",
        "order_type": "market",
        "side": "buy",
        "cash_amount": "5001",
    },
)
order = response.json()
Expect order.cancelled and a terminal status of cancelled. No trade.executed event.

Partial fill

import requests

response = requests.post(
    "https://api.engine.usesophic.com/accounts/{account_id}/orders",
    headers={
        "Authorization": "Bearer YOUR_ACCESS_TOKEN",
        "Content-Type": "application/json",
    },
    json={
        "instrument": "ins_xyz789",
        "order_type": "market",
        "side": "buy",
        "cash_amount": "5002",
    },
)
order = response.json()
Expect trade.executed followed by order.filled. The trade should reflect a partial fill (about 40% of the order); check the response for exact amounts.

Sell partial fill

Use quantity: "20" and omit cash_amount:
import requests

response = requests.post(
    "https://api.engine.usesophic.com/accounts/{account_id}/orders",
    headers={
        "Authorization": "Bearer YOUR_ACCESS_TOKEN",
        "Content-Type": "application/json",
    },
    json={
        "instrument": "ins_xyz789",
        "order_type": "market",
        "side": "sell",
        "quantity": "20",
    },
)
order = response.json()
Expect trade.executed with quantity of 5, then order.filled.

Sell full fill

Use a quantity of "12" or less (for example "10") and omit cash_amount:
import requests

response = requests.post(
    "https://api.engine.usesophic.com/accounts/{account_id}/orders",
    headers={
        "Authorization": "Bearer YOUR_ACCESS_TOKEN",
        "Content-Type": "application/json",
    },
    json={
        "instrument": "ins_xyz789",
        "order_type": "market",
        "side": "sell",
        "quantity": "10",
    },
)
order = response.json()
Expect trade.executed with quantity of 10, then order.filled.

Tracking results

Subscribe to webhooks for real-time updates, or poll Retrieve order after each placement. Webhook delivery is at-least-once; deduplicate using the event ID or Webhook-Id header.
Sandbox execution does not mirror production routing, venue behavior, or FIX lifecycles. Use it to test your integration against predictable order and trade outcomes, not to validate production execution logic.