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