Backpack Exchange API: ED25519 auth, 70 endpoints, and the official Rust SDK
Backpack Exchange offers a full REST and WebSocket API backed by ED25519 keypair signing. The official SDK is Rust-only; community Python clients cover all 70 endpoints. Here is the complete developer picture: auth, market data, order management, capital, and real-time streams.
devrels.xyz/a/119short linkBackpack Exchange is a Solana-native exchange built by the team behind the Anchor framework, the xNFT standard, and the Backpack wallet. Unlike most centralised exchanges, Backpack's API uses ED25519 keypair authentication — the same cryptographic primitive as Solana itself. There is no API secret string to leak; there is a private key you sign requests with and a public key the server verifies against. The official documentation is at docs.backpack.exchange and the official Rust client at github.com/backpack-exchange/bpx-api-client.
Authentication
All state-mutating requests require four headers. The signature covers the instruction string (method + path + body parameters, sorted) plus timestamp and window, signed with your ED25519 private key.
import { Keypair } from "@solana/web3.js";
import nacl from "tweetnacl";
const keypair = Keypair.generate(); // or load from file
const publicKey = Buffer.from(keypair.publicKey.toBytes()).toString("base64");
function signRequest(
method: string,
path: string,
params: Record<string, string>,
timestamp: number,
window = 5000
): string {
// Build the instruction string
const sorted = Object.entries(params)
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join("&");
const instruction = [`instruction=${method}${path}`, sorted, `timestamp=${timestamp}`, `window=${window}`]
.filter(Boolean)
.join("&");
const sig = nacl.sign.detached(
Buffer.from(instruction),
keypair.secretKey
);
return Buffer.from(sig).toString("base64");
}
// Request headers
const headers = {
"X-API-Key": publicKey,
"X-Signature": signRequest("GET", "/api/v1/capital", {}, Date.now()),
"X-Timestamp": Date.now().toString(),
"X-Window": "5000", // ms — replay attack window
};The X-Window parameter sets how long a signed request remains valid (default 5000ms, maximum 60000ms). Requests arriving outside the window are rejected, preventing replay attacks. Public endpoints — market data, assets, tickers — require no headers.
REST endpoints
The REST base URL is https://api.backpack.exchange/. Endpoints split into two host prefixes: /api/v1/ for trading operations and /wapi/v1/ for capital management (deposits, withdrawals).
# ── Market data (public, no auth) ──────────────────────────────────
GET /api/v1/assets # all tradeable assets
GET /api/v1/markets # all markets with specs
GET /api/v1/ticker?symbol= # single ticker
GET /api/v1/tickers # all tickers
GET /api/v1/depth?symbol= # order book (default 1000 levels per side)
GET /api/v1/klines?symbol=&interval= # OHLCV candles
GET /api/v1/fundingRates # perpetual funding
GET /api/v1/markPrices # mark + index prices
# ── Orders (authenticated) ──────────────────────────────────────────
GET /api/v1/order?symbol=&orderId= # single open order
POST /api/v1/order # execute order
DELETE /api/v1/order # cancel order
GET /api/v1/orders?symbol= # all open orders
DELETE /api/v1/orders # cancel all open orders
POST /api/v1/orders # batch order submit
# ── Capital (authenticated) ─────────────────────────────────────────
GET /api/v1/capital # balances
GET /wapi/v1/capital/deposits # deposit history
GET /wapi/v1/capital/deposit/address # deposit address
GET /wapi/v1/capital/withdrawals # withdrawal history
POST /wapi/v1/capital/withdrawals # request withdrawal
# ── Futures (authenticated) ─────────────────────────────────────────
GET /api/v1/futures/position # open futures positions
# ── Borrow / Lend (authenticated) ───────────────────────────────────
GET /api/v1/borrow-lend/positions # lending positions
# ── RFQ — Request for Quote (authenticated) ─────────────────────────
POST /api/v1/rfq # create RFQ
GET /api/v1/rfq/quote # get quote
POST /api/v1/rfq/accept # accept quote
POST /api/v1/rfq/cancel # cancel RFQ
POST /api/v1/rfq/refresh # refresh quote
# ── Vault (authenticated) ───────────────────────────────────────────
POST /api/v1/vault/mint # mint vault tokens
POST /api/v1/vault/redeem # redeem vault tokensOrder execution
Backpack processes all orders through a single linear command stream into one matching engine, regardless of how many API clients are connected. Order IDs are now randomly generated (changed June 2025 from timestamp-derived). Orders support stop-loss and take-profit fields natively.
// Execute a limit order
const payload = {
symbol: "SOL_USDC",
side: "Bid", // "Bid" | "Ask"
orderType: "Limit",
price: "145.50",
quantity: "1.0",
timeInForce: "GTC", // GTC | IOC | FOK
// Optional: stop-loss and take-profit
stopLossPrice: "140.00",
takeProfitPrice: "155.00",
};
const res = await fetch("https://api.backpack.exchange/api/v1/order", {
method: "POST",
headers: { ...authHeaders, "Content-Type": "application/json" },
body: JSON.stringify(payload),
});WebSocket streams
Real-time data streams from wss://ws.backpack.exchange/. Subscribe to multiple channels in one connection.
const ws = new WebSocket("wss://ws.backpack.exchange/");
ws.onopen = () => {
// Public streams — no auth needed
ws.send(JSON.stringify({
method: "SUBSCRIBE",
params: [
"ticker.SOL_USDC", // real-time ticker
"depth.SOL_USDC", // order book updates
"trade.SOL_USDC", // trade feed
"kline.SOL_USDC.1m", // 1-minute candles
],
}));
// Private streams — signed subscription
ws.send(JSON.stringify({
method: "SUBSCRIBE",
params: ["account.orderUpdate"], // requires auth headers
signature: [...], // ED25519 signed subscription
}));
};
ws.onmessage = (msg) => {
const data = JSON.parse(msg.data);
// data.stream: "ticker.SOL_USDC" | "depth.SOL_USDC" | ...
};The Rust SDK
The official client at github.com/backpack-exchange/bpx-api-client is Rust-only. It wraps all REST and WebSocket endpoints with typed request/response structs, handles ED25519 signing internally, and requires only your base64-encoded secret key to initialise.
use bpx_api_client::{BACKPACK_API_BASE_URL, BpxClient};
#[tokio::main]
async fn main() {
let client = BpxClient::init(
BACKPACK_API_BASE_URL.to_string(),
"your_base64_secret_key",
None, // optional extra headers
).expect("failed to init client");
// Market data — no auth needed
let markets = client.get_markets().await.unwrap();
println!("markets: {}", markets.len());
// Open orders for a symbol
let orders = client.get_open_orders(Some("SOL_USDC")).await.unwrap();
println!("open orders: {:?}", orders);
// Account balances
let balances = client.get_balances().await.unwrap();
println!("balances: {:?}", balances);
// Execute an order
let order = client.execute_order(ExecuteOrderPayload {
symbol: "SOL_USDC".into(),
side: Side::Bid,
order_type: OrderType::Limit,
price: Some("145.50".into()),
quantity: "1.0".into(),
..Default::default()
}).await.unwrap();
}
// Build from source
// cd rust && just build
// cargo add bpx-api-clientPython SDK (community)
The community backpack-exchange-sdk on PyPI covers all 70 endpoints including REST and WebSocket and is the fastest path if you are not working in Rust.
pip install backpack-exchange-sdkfrom backpack_exchange_sdk.authenticated import AuthenticationClient
client = AuthenticationClient(
public_key="your_base64_public_key",
secret_key="your_base64_secret_key"
)
# Balances
balances = client.get_balances()
# Place order
order = client.execute_order(
symbol="SOL_USDC",
side="Bid",
order_type="Limit",
price="145.50",
quantity="1.0",
time_in_force="GTC"
)
# Cancel all open orders for a symbol
client.cancel_open_orders("SOL_USDC")Rate limits
Limits are applied per sub-account: 2000 requests per minute across standard REST endpoints, 30 requests per minute for historical market data endpoints. WebSocket connections are not rate-limited by request count but are subject to connection-level limits.
# Check current rate limit headers on any response:
# X-RateLimit-Limit: 2000
# X-RateLimit-Remaining: 1998
# X-RateLimit-Reset: 1719600000000Keep reading
Collector Crypt has a marketplace program (non-custodial, delegation-based), a gacha program with RFC 9381 VRF for provably fair pack opens, and a shipping API for physical card vault operations. API partnerships are rolling out. Here's what's available to build on today.
TxODDS publishes Merkle roots of every data packet to Solana, making sports data tamper-evident and independently verifiable. Developers subscribe on-chain using TxL tokens (USDT → TxL → program subscription → API token), then query live odds, scores, and settlement feeds. Free tier covers the 2026 World Cup.
An audit report is worthless if you can't confirm the deployed bytecode is what was audited. Solana verified builds fix that: a Docker-pinned toolchain produces a deterministic .so, its hash is compared to the on-chain program data, and the result is written to a PDA anyone can read. Solana Explorer shows a verified badge. Here's the full workflow.
Get new articles in your inbox
Technical deep-dives on Solana tooling, infrastructure, and ecosystem. No noise.