Orders
Place and cancel orders on the matching engine. Authenticate with your API key from the web app API section.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /api/orders/ | Create order |
POST | /api/orders/approve | Pre-approve spend for a property |
POST | /api/orders/cancel | Cancel order |
POST | /api/orders/cancel-all | Cancel all open orders |
POST | /api/orders/conditional | Create a stop or take order. See Stop & take orders. |
POST | /api/orders/conditional/cancel | Cancel a stop or take order. See Stop & take orders. |
Create order
POST /api/orders/
Submits an order for the authenticated user.
Nonce is no longer required. Do not call POST /api/orders/nonce and do not send nonce on create.
Request body
Type: OrderRequestBody (@loafmarkets/shared-types)
interface OrderRequestBody {
tokenName: string; // lowercase slug, e.g. "opera" — not the ticker
price: number;
quantity: number;
side: 'BUY' | 'SELL';
type: 'MARKET' | 'LIMIT';
timeInForce: 'GTC';
deadline: number;
tpPrice?: number; // BUY only: attach a take-profit
slPrice?: number; // BUY only: attach a stop-loss
}Request
import axios from 'axios';
import type { OrderRequestBody } from '@loafmarkets/shared-types';
const body: OrderRequestBody = {
tokenName: 'opera',
price: 125.5,
quantity: 10,
side: 'BUY',
type: 'LIMIT',
timeInForce: 'GTC',
deadline: 0,
};
const response = await axios.post('https://api.loafmarkets.com/api/orders/', body, {
headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` },
});
console.log(response.data);Identify the market with lowercase tokenName (e.g. opera), not the short ticker (OPR) and not propertyId. For a market order, set "type": "MARKET" and "price": 0. See the Python bot template for a higher-level SDK.
Minimum order notional is 10 USDC (price × quantity), waived only for a SELL that closes your entire position.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
tokenName | string | Yes | (body) Lowercase property tokenName (letters a-z only, max 20). Not the ticker. |
price | number | Yes | (body) Limit price in USDC. Use 0 for market orders (MARKET_ORDER_PRICE). |
quantity | number | Yes | (body) Order size in tokens (max 1 decimal place). |
side | 'BUY' | 'SELL' | Yes | (body) Order side. |
type | 'MARKET' | 'LIMIT' | Yes | (body) Order type. |
timeInForce | 'GTC' | Yes | (body) Time in force (currently GTC only). |
deadline | number | Yes | (body) Unix timestamp (seconds). Use 0 for standard GTC orders. |
tpPrice | number | No | (body) BUY only. Trigger price of a take-profit SELL for the full quantity (max 2 decimal places). |
slPrice | number | No | (body) BUY only. Trigger price of a stop-loss SELL for the full quantity (max 2 decimal places). |
tpPrice and slPrice create a linked take-profit and stop-loss. When one of them triggers, Loaf cancels the other one. Omit both fields for a normal order. See Attach take-profit and stop-loss to a buy for the rules.
Response
Type: OrderApiResponse
interface OrderApiResponse {
success: boolean;
orderId: number;
errorMessage?: string;
}Example response:
{
"success": true,
"orderId": 9001
}Errors
| Status | Code | Description |
|---|---|---|
400 | validation_error | Request failed schema validation. |
401 | unauthorized | Missing or invalid authentication. |
403 | — | Trading closed, halted, ineligible for competition, or world gate rejected the property. |
404 | not_found | Unknown tokenName. |
503 | — | Matching engine unreachable or did not confirm — see callout below. |
500 | internal_error | Unexpected server error. |
503 on create: do not blind-retry. If the engine is unreachable before commit, the order was not placed (safe to retry after backoff). If the transport fails after commit, funds may already be frozen and the order may still be processing. Check open orders / portfolio before sending another identical order.
Requires API key authentication.
Approve trading
POST /api/orders/approve
Pre-approves spend allowances for a property ahead of the first order (BUY and SELL sides). Identify the market with lowercase tokenName.
Request body
Type: ApproveTradingRequestBody
interface ApproveTradingRequestBody {
tokenName: string;
}Request
import axios from 'axios';
import type { ApproveTradingRequestBody } from '@loafmarkets/shared-types';
const body: ApproveTradingRequestBody = { tokenName: 'opera' };
const response = await axios.post('https://api.loafmarkets.com/api/orders/approve', body, {
headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` },
});
console.log(response.data);Response
Type: ApproveTradingResponse
interface ApproveTradingResponse {
approved: true;
results: {
BUY: { alreadyApproved: boolean };
SELL: { alreadyApproved: boolean };
};
}alreadyApproved: true means the wallet already held a sufficient allowance (no on-chain tx sent for that side).
Errors
| Status | Code | Description |
|---|---|---|
400 | validation_error | Request failed schema validation. |
401 | unauthorized | Missing or invalid authentication. |
404 | not_found | Unknown tokenName. |
500 | internal_error | Unexpected server error. |
Cancel order
POST /api/orders/cancel
Cancels an existing order via the matching engine.
To cancel a stop or take order that has not triggered, use Cancel a stop or take order.
Request body
Type: CancelOrderRequestBody (@loafmarkets/shared-types)
interface CancelOrderRequestBody {
orderId: number;
}Request
import axios from 'axios';
import type { CancelOrderRequestBody } from '@loafmarkets/shared-types';
const body: CancelOrderRequestBody = {
orderId: 9001,
};
const response = await axios.post('https://api.loafmarkets.com/api/orders/cancel', body, {
headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` },
});
console.log(response.data);Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orderId | number | Yes | (body) ID of the order to cancel. |
Response
Type: CancelOrderResponse
interface CancelOrderResponse {
success: boolean;
orderId: number;
errorMessage?: string;
}Example response:
{
"success": true,
"orderId": 9001
}Errors
| Status | Code | Description |
|---|---|---|
400 | validation_error | Request failed schema validation. |
401 | unauthorized | Missing or invalid authentication. |
404 | not_found | Resource not found (where applicable). |
500 | internal_error | Unexpected server error. |
Requires API key authentication.
Cancel all orders
POST /api/orders/cancel-all
Cancels every open order for the authenticated user by relaying a cancel request to the matching engine for each one.
It also cancels your stop and take orders with status PENDING or ARMED. Their ids come first in cancelledOrderIds, and requestedCount includes them.
Request
import axios from 'axios';
const response = await axios.post('https://api.loafmarkets.com/api/orders/cancel-all', undefined, {
headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` },
});
console.log(response.data);Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| None | - | No | No parameters for this endpoint. |
Response
Type: CancelAllOrdersResponse (@loafmarkets/shared-types)
interface CancelAllOrdersResponse {
requestedCount: number;
cancelledOrderIds: number[];
failedOrders: Array<{ orderId: number; errorMessage: string }>;
}Example response:
{
"requestedCount": 2,
"cancelledOrderIds": [9001, 9002],
"failedOrders": []
}Errors
| Status | Code | Description |
|---|---|---|
401 | unauthorized | Missing or invalid authentication. |
503 | service_unavailable | Matching engine unavailable for all cancels. |
500 | internal_error | Unexpected server error. |
Requires API key authentication. Partial success is possible: check failedOrders when cancelledOrderIds does not cover every open order.