Skip to Content
GuidesBuilding a trading bot

Building a trading bot

This guide walks through a minimal bot on the Loaf dev environment: create an account, issue an API key, inspect a market and its order book, place a limit order, then cancel it. A short strategy sketch at the end shows how you might extend the same flow into a simple quoting loop.

For a batteries-included Python SDK and runnable template, see the loaf-python-api-bot-template  repository on GitHub.

Environment: Examples use https://api.loafmarkets.com as the API base and placeholder asset sunset-villa (propertyId 42). Do not run this tutorial against production with real funds until you have tested on dev and reviewed compliance requirements.

What you will build

StepGoal
1Sign up on api.loafmarkets.com 
2Create an API key in the API settings UI 
3Load market metadata (Info API) and subscribe to the order book over WebSocket
4Submit a limit order (nonce → submit)
5Cancel that order

Prerequisites

  • A modern browser and terminal with curl and jq (optional, for shell examples)
  • Node.js 20+ if you run the TypeScript snippets
  • Basic familiarity with REST and environment variables

Configuration

Set these once for the rest of the guide:

export LOAF_API_BASE="https://api.loafmarkets.com" export LOAF_TOKEN_NAME="sunset-villa" export LOAF_PROPERTY_ID=42 export LOAF_API_KEY="your-api-key" # shown once when you create the key (step 2)
VariablePurpose
LOAF_API_BASEDev API host (all paths are under /api/...)
LOAF_TOKEN_NAMELowercase property token symbol for Info routes
LOAF_PROPERTY_IDNumeric property ID for Orders routes
LOAF_API_KEYProgrammatic key from the API settings UI (step 2)

The Python SDK template  uses different env names: LOAF_API_BASE_URL (host including /api), LOAF_TARGET_TOKEN (resolves propertyId for you), plus optional LOAF_USER_ID and LOAF_WS_URL. The variables above are for the curl / TypeScript examples in this guide.

All authenticated requests in this guide — reads, orders, history — use the same API key:

# Authorization: Bearer $LOAF_API_KEY

1. Create your Loaf account

  1. Open https://api.loafmarkets.com/ .
  2. Choose Sign up and register with email or connect a Web3 wallet. Either path creates a self-custodial Loaf account suitable for API trading.
  3. Complete any onboarding prompts in the app (wallet setup, profile, and KYC if you plan to move fiat or trade size that requires verification).

Bots are available to all account types on dev; production may impose additional account or KYC checks (for example wholesale offerings). See Offerings when you need primary-market subscription.

Store recovery and wallet credentials securely. Loaf does not hold your keys; lost access cannot be reset through support in the same way as a centralized exchange password.


2. Create an API key

Programmatic access uses an API key you manage in the product UI—not your login password.

  1. Sign in on dev and go to https://api.loafmarkets.com/api .
  2. Create a key with a clear label (for example trading-bot-dev).
  3. Copy the secret immediately; it is shown only once. Export it as LOAF_API_KEY.

You can rotate keys by revoking old ones in the same UI. HTTP key management is not part of the public API reference—the UI is the recommended path for your first bot.

Send the API key as Authorization: Bearer $LOAF_API_KEY on every authenticated endpoint in this guide — market reads, order placement, cancellation, and history.


3. Read the market and orders on the book

Before quoting or crossing the spread, load market context (Info API) and the central limit order book (resting bids and asks) for your token.

Market metadata

GET /api/info/:tokenName/header returns display fields, identifiers (including propertyId), and trading-related header data for the property page.

import axios from 'axios'; const base = process.env.LOAF_API_BASE ?? 'https://api.loafmarkets.com'; const tokenName = process.env.LOAF_TOKEN_NAME ?? 'sunset-villa'; const { data: header } = await axios.get( `${base}/api/info/${tokenName}/header`, { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); console.log('propertyId:', header.propertyId); console.log('header:', header);

Use header.propertyId to confirm it matches LOAF_PROPERTY_ID before sending orders.

GET /api/info/:tokenName/overview adds longer-form property content (useful for bots that gate trading on disclosure or status flags):

curl -sS "$LOAF_API_BASE/api/info/$LOAF_TOKEN_NAME/overview" \ -H "Authorization: Bearer $LOAF_API_KEY" | jq .

You can also list tradeable properties and fetch an embedded order-book snapshot via GET /api/trade and GET /api/trade/:tokenName (no auth required). See Trade for full schemas, or the Python template  for runnable examples.

See Info for property disclosure endpoints.

Orders on the book

Resting bids and asks are streamed on the Loaf WebSocket API. Connect to wss://<host>/ws (for dev, derived from your API host), send an auth frame with your API key if you need private channels, then subscribe to orderbook:{propertyId} using the propertyId from the Info header above. Updates use type orderbook_update with bids and asks arrays (each level has price, quantity, and orderId).

Example message shape:

{ "type": "orderbook_update", "propertyId": 42, "bids": [{ "price": 124.0, "quantity": 5.0, "orderId": 8801 }], "asks": [{ "price": 126.0, "quantity": 3.0, "orderId": 8802 }] }

Use the book to choose prices: join the best bid, improve by one tick, or passively quote inside the spread. Your own open orders may appear in the book until they fill or you cancel them. Until WebSocket wiring is in place, you can reconcile resting orders via History (GET /api/history/orders/active). See WebSocket for trades, chart, mark price, volume, IPO, and private portfolio channels.

4. Place an order

Order placement is a two-step flow: nonce → submit.

  1. POST /api/orders/nonce → receive nonce and deadline
  2. POST /api/orders/ with the order body → receive orderId

Both steps use your API key. Each order needs a fresh nonce — do not reuse one.

Trading gate: Your account must have trading enabled (for example, a redeemed referral code, or competition admission when a round is active). Set this up in the Loaf web app before placing orders; otherwise the API returns a 403 error.

4a. Request a nonce

const { data: noncePayload } = await axios.post( `${base}/api/orders/nonce`, undefined, { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); const { nonce, deadline } = noncePayload;

4b. Build the order

Construct a limit order below the best ask for a tutorial buy so it rests on the book instead of crossing (adjust prices using step 3 book data).

const order = { propertyId: Number(process.env.LOAF_PROPERTY_ID ?? 42), price: 120.0, quantity: 1, side: 'BUY' as const, type: 'LIMIT' as const, timeInForce: 'GTC' as const, deadline: 0, nonce, };

For a market order, set "type": "MARKET" and "price": 0. See Orders — Create order.

4c. Submit the order

const { data: placed } = await axios.post(`${base}/api/orders/`, order, { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` }, }); if (!placed.success) { throw new Error(placed.errorMessage ?? 'Order rejected'); } const orderId = placed.orderId; console.log('placed orderId:', orderId);

A 200 with success: true means the exchange accepted the order into the book — not that it filled. Fills arrive asynchronously on your private portfolio:{userId} WebSocket channel (set LOAF_USER_ID to your numeric user id from the web app).

Save orderId from the response (example: 9001). Re-fetch the book from step 3 to see your order listed among resting bids.


5. Cancel the order

Cancel with POST /api/orders/cancel and the orderId from step 4. Use the same API key as placement.

const { data: cancelled } = await axios.post( `${base}/api/orders/cancel`, { orderId: placed.orderId }, { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` } }, ); console.log(cancelled);

Confirm cancellation by polling GET /api/history/orders/active until the order disappears, or until your orderId is gone from the WebSocket book feed.


Strategy sketch

Once the tutorial steps work, a simple market-making sketch might look like this:

  1. Subscribe to orderbook:{propertyId} (or poll History while building WebSocket support).
  2. Compute a quote: e.g. best bid + tick for your bid, best ask − tick for your ask, sized to a max inventory cap.
  3. Reconcile your resting orders (compare book entries to your last known orderIds).
  4. Replace stale quotes: cancel via POST /api/orders/cancel, request a new nonce, and POST /api/orders/.
  5. Stop on risk events: wide spread, missing book side, or success: false from the API.

Control loop: fetch book → if spread is acceptable, cancel stale quotes → nonce, place → sleep → repeat. If the spread is too wide or the book is empty, sleep and alert instead of quoting.

The Python bot template  implements this pattern with a threaded WebSocket feed and a 5-second on_tick loop you can replace with your own logic.

Hardening checklist for anything beyond dev:

  • Idempotency: track nonces and orderIds locally; never reuse a nonce.
  • Secrets: store the API key in a vault; never commit .env.
  • Observability: log HTTP status, errorMessage, and book snapshots on failures.
  • Compliance: KYC, position limits, and jurisdiction rules before production capital.

Reference

TopicLink
Info (header, overview)Info API
Nonce, place, cancelOrders API
Your fills and historyHistory API
Python SDK + bot templateloaf-python-api-bot-template 
Dev appapi.loafmarkets.com 
API keys UIapi.loafmarkets.com/api 
Last updated on