API Reference
On-Chain Integration
Settled's core trading logic runs on a Solana program. The backend provides endpoints to bridge on-chain actions with the Postgres state layer.
Architecture Overview
User Wallet
│
├─ signs buy_shares / sell_shares instruction
│
▼
Solana Program (Settled)
│
├─ validates + executes trade on-chain
│
▼
POST /v1/trade/confirm ← user calls after tx confirms
│
▼
Postgres (balance, positions, trade history)
The backend never holds a user's private key. It only:
- Lazily creates market PDAs when needed
- Co-signs
create_markettransactions with the program authority keypair - Syncs confirmed on-chain transactions to the database
Market PDAs
Each market has a Program Derived Address (PDA) on Solana. PDAs are created lazily on first use.
Ensure Market is On-Chain
GET /v1/markets/{id}/ensure-onchain
Checks if the market PDA exists. If not, creates it. Call this before constructing any trade transaction for a market.
Requires JWT.
curl https://api.settled.pro/v1/markets/8166597e-.../ensure-onchain \
-H "Authorization: Bearer <jwt>"
Response (PDA already exists):
{
"data": {
"market_id": "8166597e-...",
"pda": "FxMb3z7qHvTkLpWgNe4r...",
"status": "ready"
}
}
Response (PDA needs creation):
{
"data": {
"market_id": "8166597e-...",
"status": "needs_cosign",
"transaction": "<base64_unsigned_tx>"
}
}
If status is needs_cosign, sign the transaction and submit it to POST /v1/markets/{id}/co-sign.
Co-Sign Market Creation Transaction
POST /v1/markets/{id}/co-sign
The backend co-signs the create_market transaction with the program authority key. You provide your partial signature; the backend adds its signature and returns the fully-signed transaction for you to submit to Solana.
Requires JWT. Anti-replay headers required.
transactionstringrequiredBase64-encoded partially-signed Solana transaction
curl -X POST https://api.settled.pro/v1/markets/8166597e-.../co-sign \
-H "Authorization: Bearer <jwt>" \
-H "X-Request-Nonce: a3f8b2c1d4e5f69702ab3c4d5e6f7081" \
-H "X-Request-Timestamp: 1742298600" \
-H "Content-Type: application/json" \
-d '{"transaction": "<base64_partial_tx>"}'
Response:
{
"data": {
"transaction": "<base64_cosigned_tx>"
}
}
Submit the returned transaction to Solana:
const txBytes = Buffer.from(data.transaction, 'base64')
const tx = Transaction.from(txBytes)
const sig = await connection.sendRawTransaction(tx.serialize())
await connection.confirmTransaction(sig)
Confirm a Trade
After your buy_shares or sell_shares transaction confirms on-chain, call this endpoint to sync the trade to Postgres.
POST /v1/trade/confirm
Requires JWT. Anti-replay headers required.
market_idstringrequiredMarket UUID
tx_sigstringrequiredConfirmed Solana transaction signature
sidestringrequiredyes or no
sharesstringrequiredNumber of shares purchased or sold
curl -X POST https://api.settled.pro/v1/trade/confirm \
-H "Authorization: Bearer <jwt>" \
-H "X-Request-Nonce: b4c9d3e2f1a0b5c6d7e8f9a0b1c2d3e4" \
-H "X-Request-Timestamp: 1742298605" \
-H "Content-Type: application/json" \
-d '{
"market_id": "8166597e-...",
"tx_sig": "5KtWMrqHvTkLpWgNe4r...",
"side": "yes",
"shares": "13.698630"
}'
Response:
{
"data": {
"trade_id": "a1b2c3d4-...",
"side": "yes",
"shares": "13.698630",
"cost_usdc": "10.000000",
"fee_usdc": "0.100000",
"new_yes_price": "0.742000",
"new_no_price": "0.258000"
}
}
Your balance and positions are updated immediately in Postgres.
Full Trade Flow (TypeScript)
import { Connection, Transaction, PublicKey } from '@solana/web3.js'
const API = 'https://api.settled.pro/v1'
const connection = new Connection('https://api.mainnet-beta.solana.com')
async function buyShares(marketId: string, side: 'yes' | 'no', usdcAmount: number) {
// 1. Ensure market is on-chain
const ensureRes = await fetch(`${API}/markets/${marketId}/ensure-onchain`, {
headers: { 'Authorization': `Bearer ${jwt}` }
})
const { data: ensureData } = await ensureRes.json()
if (ensureData.status === 'needs_cosign') {
// Sign and co-sign create_market tx
const tx = Transaction.from(Buffer.from(ensureData.transaction, 'base64'))
const signed = await wallet.signTransaction(tx)
const b64 = signed.serialize({ requireAllSignatures: false }).toString('base64')
const cosignRes = await fetch(`${API}/markets/${marketId}/co-sign`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwt}`,
'X-Request-Nonce': nonce(),
'X-Request-Timestamp': ts(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ transaction: b64 })
})
const { data: cosignData } = await cosignRes.json()
const finalTx = Transaction.from(Buffer.from(cosignData.transaction, 'base64'))
const sig = await connection.sendRawTransaction(finalTx.serialize())
await connection.confirmTransaction(sig)
}
// 2. Get a quote
const quoteRes = await fetch(`${API}/markets/${marketId}/quote?side=${side}&amount=${usdcAmount}`)
const { data: quote } = await quoteRes.json()
console.log(`Expected: ${quote.shares} shares, price impact: ${quote.price_impact}`)
// 3. Build and sign buy_shares instruction
// ... construct Solana transaction for buy_shares ...
const tradeTx = buildBuySharesTx(ensureData.pda, side, usdcAmount)
const signedTrade = await wallet.signTransaction(tradeTx)
const tradeSig = await connection.sendRawTransaction(signedTrade.serialize())
await connection.confirmTransaction(tradeSig)
// 4. Confirm trade to Postgres
const confirmRes = await fetch(`${API}/trade/confirm`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${jwt}`,
'X-Request-Nonce': nonce(),
'X-Request-Timestamp': ts(),
'Content-Type': 'application/json'
},
body: JSON.stringify({
market_id: marketId,
tx_sig: tradeSig,
side,
shares: quote.shares
})
})
const { data: trade } = await confirmRes.json()
return trade
}
function nonce() { return crypto.randomUUID().replace(/-/g, '') }
function ts() { return Math.floor(Date.now() / 1000).toString() }