Skip to main content
This guide shows the full flow using the REST API. You’ll need a Solana wallet with SOL (for transaction fees) and USDC (for trading).

Prerequisites

  • A Solana wallet with SOL and USDC
  • Node.js 18+ installed
  • @solana/web3.js, @solana/spl-token, bs58, and tweetnacl installed

1. Setup

import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js";
import nacl from "tweetnacl";
import bs58 from "bs58";

const connection = new Connection("https://api.mainnet-beta.solana.com", "confirmed");
const wallet = Keypair.fromSecretKey(bs58.decode(process.env.PRIVATE_KEY));
const API = "https://api.pmx.trade";
const pubkey = wallet.publicKey.toBase58();

async function signAndSend(base64Tx) {
  const tx = VersionedTransaction.deserialize(Buffer.from(base64Tx, "base64"));
  tx.sign([wallet]);
  const sig = await connection.sendRawTransaction(tx.serialize());
  await connection.confirmTransaction(sig, "confirmed");
  return sig;
}

2. Deposit USDC

Before trading, deposit USDC into your personal on-chain smart wallet. Your balance is the actual SPL token balance in your smart wallet and you can withdraw anytime.
// Check if already set up (has smart wallet balance > 0)
const setupRes = await fetch(`${API}/v2/clob/account/setup?pubkey=${pubkey}`);
const { ready, smartWalletBalance } = await setupRes.json();

if (!ready) {
  // Deposit 100 USDC (raw units, 6 decimals)
  const depositRes = await fetch(`${API}/v2/clob/account/deposit`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ pubkey, amount: "100000000" }),
  });
  const { transaction } = await depositRes.json();
  const sig = await signAndSend(transaction);
  console.log("USDC deposited:", sig);
}
You can deposit additional USDC at any time. Your smart wallet balance is available for trading immediately after the deposit transaction confirms. Withdraw anytime via /account/withdraw.

3. Find a Market

Browse available markets and check the orderbook:
const marketsRes = await fetch(`${API}/v2/clob/markets`);
const { markets } = await marketsRes.json();
const market = markets.find(m => m.status === "active");

console.log(market.title, market.status);
console.log("Best bid YES:", market.bestBid.yes, "Best ask YES:", market.bestAsk.yes);
{
  "id": "550e8400-...",
  "title": "Will BTC hit $100k by end of 2025?",
  "status": "active",
  "bestBid": { "yes": 5500, "no": 4200 },
  "bestAsk": { "yes": 5800, "no": 4500 }
}

4. Place Your First Order

Buy 50 YES tokens at $0.55 (5500 bps):
const orderMessage = {
  market: market.marketPubkey,
  owner: pubkey,
  side: 0,         // 0 = buy
  outcome: 0,      // 0 = yes
  priceBps: 5500,  // $0.55 per token
  quantity: "50000000",   // 50 tokens (raw units, 6 decimals)
  nonce: Date.now().toString(),
  expiry: Math.floor(Date.now() / 1000 + 86400).toString(), // 24h
};

// Serialize and sign the order message (Borsh format, 92 bytes)
// See full lifecycle guide for signing implementation details
const orderSignature = signOrderMessage(orderMessage, wallet);

const orderRes = await fetch(`${API}/v2/clob/orders`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    orderMessage,
    signature: orderSignature,
    orderType: "limit",
    timeInForce: "gtc",
  }),
});
const { orderId, status, fills } = await orderRes.json();

console.log("Order placed:", orderId, "Status:", status);
if (fills.length > 0) {
  console.log(`Immediately filled ${fills.length} match(es)!`);
}
Use orderType: "market" to fill immediately at the best available price. Use "limit" to set your own price and wait for a match.
No authentication token is needed — the Ed25519 signature on the order message proves identity. The on-chain program verifies this signature during settlement.

5. Check Your Balances

See your smart wallet balance, USDC, and token positions:
const balancesRes = await fetch(`${API}/v2/clob/account/balances?pubkey=${pubkey}`);
const { smartWalletBalance, withdrawable, walletBalance, totalCommitted, markets: marketBalances } = await balancesRes.json();

console.log(`Smart Wallet Balance: $${(Number(smartWalletBalance) / 1e6).toFixed(2)}`);
console.log(`Withdrawable: $${(Number(withdrawable) / 1e6).toFixed(2)}`);
console.log(`Wallet Balance: $${(Number(walletBalance) / 1e6).toFixed(2)}`);
console.log(`In Orders: $${(Number(totalCommitted) / 1e6).toFixed(2)}`);

for (const bal of marketBalances) {
  if (bal.yesTokens !== "0" || bal.noTokens !== "0") {
    console.log(`  ${bal.marketSlug}: ${bal.yesTokens} YES, ${bal.noTokens} NO`);
  }
}

Next Steps

Full Lifecycle

Complete walkthrough including selling, redemption, and fill history

Conditional Tokens

How split, merge, and redeem work under the hood

API Reference

Full endpoint reference with request/response examples