Placing and cancelling needs a read_write key. The examples run on the US demo exchange with 1-cent buy orders that will not fill. How orders behave on the exchange is covered in Order types and Risk controls; this page shows the SDK calls.
The examples use a market that is open, accepting orders (trading is true), and whose event has not started:
import { STX } from "@stxapp/stx-typescript";
const client = new STX();
let market;for await (const m of client.iterMarkets({ trading: true, sortBy: "event_start", sortDirection: "desc" })) { if (m.event_status === "scheduled") { market = m; break; }}if (!market?.market_id) throw new Error("no tradeable market");const marketId = market.market_id;Place an order
Section titled “Place an order”const order = await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1", clientOrderId: "my-order-1",});console.log(order.id, order.status);
await client.cancelOrder(order.id!);placeOrder(marketId, action, orderType, options) takes action "buy" or "sell" and orderType "limit" or "market". Options:
| Option | Type |
|---|---|
price |
Dollar string, e.g. "0.56". Required for "limit", omitted for "market" |
quantity |
Contract string, e.g. "2" |
clientOrderId |
Your own id, echoed back and filterable |
expiration, expirationTime |
See Expiration |
cancelOnDisconnect |
See Cancel-on-disconnect |
deviceId |
Optional label |
geoLocation |
See Geo-fencing |
If the exchange refuses the order, the call throws with the exchange’s message:
import { STXRejectedException, STXValidationException } from "@stxapp/stx-typescript";
try { await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1.5" });} catch (err) { if (err instanceof STXRejectedException || err instanceof STXValidationException) { console.error(err.statusCode, err.message); } else { throw err; }}A market order leaves out price:
await client.placeOrder(marketId, "buy", "market", { quantity: "1" });Place several orders
Section titled “Place several orders”const results = await client.placeOrders([ { marketId, action: "buy", orderType: "limit", price: "0.01", quantity: "1" }, { marketId, action: "buy", orderType: "limit", price: "0.02", quantity: "1" },]);for (const r of results) { console.log(r.ok ? r.order!.id : r.errors);}Each result holds either order or errors, in the order you sent them. One rejection does not stop the rest.
Cancel
Section titled “Cancel”await client.cancelOrder(orderId); // oneawait client.cancelOrders([idA, idB]); // severalawait client.cancelAllOrders(); // everything on the accountEach returns cancellations with order_id and status. An order can still fill while a cancel is in flight, so reconcile against fills.
Read orders
Section titled “Read orders”for await (const o of client.iterOrders({ status: ["open", "delayed"] })) { console.log(o.id, o.price, o.filled, "/", o.quantity);}const one = await client.order(orderId);orders() filters on orderIds, clientOrderIds, marketIds and status.
Avoid duplicate orders
Section titled “Avoid duplicate orders”The client never resends a POST after a server error or a dropped connection, because the order may already be on the book. Send a clientOrderId and look it up before trying again:
import { randomUUID } from "node:crypto";import { STXServerException, STXTransportException } from "@stxapp/stx-typescript";
const clientOrderId = randomUUID();let order;try { order = await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1", clientOrderId });} catch (err) { if (!(err instanceof STXServerException || err instanceof STXTransportException)) throw err; order = (await client.orders({ clientOrderIds: [clientOrderId] })).items[0];}Expiration
Section titled “Expiration”The two expiration modes are described in Risk controls. In the SDK:
await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1", expiration: "good_till_start" });
await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1", expiration: "good_till_time", expirationTime: (Date.now() + 10 * 60_000) * 1000, // microseconds});Cancel-on-disconnect
Section titled “Cancel-on-disconnect”How cancel-on-disconnect works is described in Risk controls. In the SDK, arm it on the orders channel and opt each order in. The client then keeps pinging the channel for you while the socket is up.
const ws = await client.websocket().connect();const orders = await ws.orders({ cancelOnDisconnect: true, pingTimeout: 5000 });console.log("granted timeout (ms):", orders.reply.ping_timeout);
await client.placeOrder(marketId, "buy", "limit", { price: "0.01", quantity: "1", cancelOnDisconnect: true });Geo-fencing
Section titled “Geo-fencing”STX Ontario checks where each order write comes from. A server at a fixed IP address needs that address whitelisted on your account. Otherwise, give the client a geolocation packet, or a function that returns a fresh one, and it is attached to every order write:
const client = new STX({ geoLocation: () => getLatestPacket() });Check before trading, without placing anything (needs a read_write key; call it once at start-up):
const check = await client.geoCheck();if (!check.allowed) console.error(check.reason, check.message);A refused write throws STXGeoLocationException with a reason.

