# Table of Contents - [Market Public API | Probable Developer](#market-public-api-probable-developer) - [API Overview | Probable Developer](#api-overview-probable-developer) - [Complete Guide: Orderbook Integration with Proxy Wallet | Probable Developer](#complete-guide-orderbook-integration-with-proxy-wallet-probable-developer) - [Overview | Probable Developer](#overview-probable-developer) - [Installation | Probable Developer](#installation-probable-developer) - [Orders | Probable Developer](#orders-probable-developer) - [Fees | Probable Developer](#fees-probable-developer) - [Quick Start | Probable Developer](#quick-start-probable-developer) - [Market Data | Probable Developer](#market-data-probable-developer) - [Proxy Wallet | Probable Developer](#proxy-wallet-probable-developer) - [Positions | Probable Developer](#positions-probable-developer) - [Search API | Probable Developer](#search-api-probable-developer) - [WebSocket | Probable Developer](#websocket-probable-developer) - [Tags API | Probable Developer](#tags-api-probable-developer) - [Markets API | Probable Developer](#markets-api-probable-developer) - [Events API | Probable Developer](#events-api-probable-developer) - [API Keys API Reference | Probable Developer](#api-keys-api-reference-probable-developer) - [Authentication API Reference | Probable Developer](#authentication-api-reference-probable-developer) - [Getting Started | Probable Developer](#getting-started-probable-developer) - [Complete Guide: Orderbook Integration with EOA Wallet | Probable Developer](#complete-guide-orderbook-integration-with-eoa-wallet-probable-developer) - [Token Approvals | Probable Developer](#token-approvals-probable-developer) - [Orders API Reference | Probable Developer](#orders-api-reference-probable-developer) - [User Data | Probable Developer](#user-data-probable-developer) - [Creating a Proxy Wallet | Probable Developer](#creating-a-proxy-wallet-probable-developer) - [Orderbook Data | Probable Developer](#orderbook-data-probable-developer) - [Orderbook API | Probable Developer](#orderbook-api-probable-developer) - [Trades API | Probable Developer](#trades-api-probable-developer) - [TypeScript SDK | Probable Developer](#typescript-sdk-probable-developer) --- # Market Public API | Probable Developer [Skip to content](https://developer.probable.markets/api/market-public/overview#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Overview On this page Chevron Right The Market Public API provides access to prediction market events, markets, and related information. Most endpoints are publicly accessible without authentication. **Base URL:** `https://market-api.probable.markets` **API Version:** 1.0.0 Overview[](https://developer.probable.markets/api/market-public/overview#overview) ------------------------------------------------------------------------------------- This API allows you to: * Browse and search events and markets * Get detailed information about specific events and markets * Filter by tags, status, and other criteria Authentication[](https://developer.probable.markets/api/market-public/overview#authentication) ------------------------------------------------------------------------------------------------- All endpoints are public and do not require authentication. Rate Limiting[](https://developer.probable.markets/api/market-public/overview#rate-limiting) ----------------------------------------------------------------------------------------------- Results are cached using Redis: * Event listings: 5 minutes * Market listings: 3 minutes * Individual events/markets: 2 minutes * Search results: 3 minutes (when cache=true) Endpoints[](https://developer.probable.markets/api/market-public/overview#endpoints) --------------------------------------------------------------------------------------- ### Events[](https://developer.probable.markets/api/market-public/overview#events) * [List Events](https://developer.probable.markets/api/market-public/events) - Get paginated list of events * [Get Event by ID](https://developer.probable.markets/api/market-public/events#get-by-id) - Get event details by numeric ID * [Get Event by Slug](https://developer.probable.markets/api/market-public/events#get-by-slug) - Get event details by slug * [Get Event Tags](https://developer.probable.markets/api/market-public/events#get-tags) - Get tags for an event ### Markets[](https://developer.probable.markets/api/market-public/overview#markets) * [List Markets](https://developer.probable.markets/api/market-public/markets) - Get paginated list of markets * [Get Market by ID](https://developer.probable.markets/api/market-public/markets#get-by-id) - Get market details by ID * [Get Market by Polymarket ID](https://developer.probable.markets/api/market-public/markets#get-by-polymarket-id) - Get market by Polymarket identifier * [Get Market by BSC Question ID](https://developer.probable.markets/api/market-public/markets#get-by-bsc-id) - Get market by BSC question ID ### Tags[](https://developer.probable.markets/api/market-public/overview#tags) * [List Tags](https://developer.probable.markets/api/market-public/tags) - Get all available tags ### Search[](https://developer.probable.markets/api/market-public/overview#search) * [Search Events and Markets](https://developer.probable.markets/api/market-public/search) - Full-text search with filtering Response Format[](https://developer.probable.markets/api/market-public/overview#response-format) --------------------------------------------------------------------------------------------------- All endpoints return JSON responses. Paginated endpoints include a `pagination` object with metadata about the results. Next Steps[](https://developer.probable.markets/api/market-public/overview#next-steps) ----------------------------------------------------------------------------------------- * [Browse Events](https://developer.probable.markets/api/market-public/events) * [Search Markets](https://developer.probable.markets/api/market-public/search) --- # API Overview | Probable Developer [Skip to content](https://developer.probable.markets/api/overview#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) API Chevron Down Menu Overview On this page Chevron Right Welcome to the Probable API documentation. Our platform provides a comprehensive set of APIs for building prediction market applications. Available Services[](https://developer.probable.markets/api/overview#available-services) ------------------------------------------------------------------------------------------- ### [Market Public API](https://developer.probable.markets/api/market-public/overview) [](https://developer.probable.markets/api/overview#market-public-api) Public API for accessing market and event information. No authentication required for most endpoints. **Base URL:** `https://market-api.probable.markets` **Features:** * Browse events and markets * Search functionality * Tag management ### [Orderbook API](https://developer.probable.markets/api/orderbook-api/overview) [](https://developer.probable.markets/api/overview#orderbook-api) Comprehensive API for trading, authentication, and data access. **Base URL:** `https://api.probable.markets` **Features:** * Authentication (L1, L2) * API key management * Order management * Orderbook data (prices, order books, historical data) * Trade history and user data Getting Started[](https://developer.probable.markets/api/overview#getting-started) ------------------------------------------------------------------------------------- 1. Choose the API service that fits your needs 2. Review the authentication requirements 3. Check the endpoint documentation 4. Start building! Authentication[](https://developer.probable.markets/api/overview#authentication) ----------------------------------------------------------------------------------- Different APIs use different authentication methods: * **Market Public API**: All endpoints are public, no authentication required * **Orderbook API**: Multi-level authentication (L1, L2) with API keys See each API's documentation for detailed authentication instructions. --- # Complete Guide: Orderbook Integration with Proxy Wallet | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-complete-guide#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Orderbook Complete Guide On this page Chevron Right This comprehensive guide walks you through the complete process of interacting with Probable Markets orderbook using a proxy wallet (Gnosis Safe). This step-by-step tutorial covers all prerequisites, setup, and the complete order placement flow. > **Alternative Flow:** If you prefer to use your EOA wallet directly without creating a proxy wallet, see the [Orderbook EOA Guide](https://developer.probable.markets/api/orderbook-eoa-guide) > for a simpler integration flow. Overview[](https://developer.probable.markets/api/orderbook-complete-guide#overview) --------------------------------------------------------------------------------------- This guide provides a complete walkthrough for integrating with Probable Markets orderbook, starting from scratch with just an EOA wallet. You'll learn how to: 1. **Create a Proxy Wallet** - Set up a Gnosis Safe smart contract wallet derived from your EOA 2. **Approve Tokens** - Grant spending allowances for USDT and CTF tokens 3. **Deposit USDT** - Transfer USDT to your proxy wallet 4. **Create API Key** - Generate API credentials for authenticated requests 5. **Create and Sign Order** - Build an EIP-712 signed order 6. **Submit Order** - Send the order to the API with L2 authentication > **Note:** This guide references the implementation in `clob-examples`. For complete working code, see the [clob-examples repository](https://github.com/0xprobable/clob-examples) > . * * * Prerequisites[](https://developer.probable.markets/api/orderbook-complete-guide#prerequisites) ------------------------------------------------------------------------------------------------- * An EOA wallet with: * BNB for transaction fees * USDT for trading (will be deposited to proxy wallet) * Access to a BSC RPC endpoint * Node.js/Bun environment with `viem` and `@safe-global/protocol-kit` installed Contract Addresses[](https://developer.probable.markets/api/orderbook-complete-guide#contract-addresses) ----------------------------------------------------------------------------------------------------------- const PROXY_FACTORY_ADDRESS = '0xB99159aBF0bF59a512970586F38292f8b9029924'; const USDT_ADDRESS = '0x55d398326f99059fF775485246999027B3197955'; const CTF_TOKEN_ADDRESS = '0x364d05055614B506e2b9A287E4ac34167204cA83'; const CTF_EXCHANGE_ADDRESS = '0xF99F5367ce708c66F0860B77B4331301A5597c86'; const CHAIN_ID = 56; // BSC Mainnet * * * Step 1: Create Proxy Wallet[](https://developer.probable.markets/api/orderbook-complete-guide#step-1-create-proxy-wallet) ---------------------------------------------------------------------------------------------------------------------------- The proxy wallet is a Gnosis Safe smart contract wallet that acts as the `maker` for your orders. It's deterministically derived from your EOA address. ### 1.1 Check if Proxy Exists[](https://developer.probable.markets/api/orderbook-complete-guide#11-check-if-proxy-exists) First, check if a proxy wallet already exists for your EOA: import { getContract } from 'viem'; import { PROXY_FACTORY_ADDRESS, PROXY_FACTORY_ABI } from './config'; async function checkProxyExists(userAddress: `0x${string}`) { const proxyFactory = getContract({ address: PROXY_FACTORY_ADDRESS, abi: PROXY_FACTORY_ABI, client: publicClient, }); const proxyAddress = await proxyFactory.read.computeProxyAddress([userAddress]); // Check if proxy is deployed const code = await publicClient.getBytecode({ address: proxyAddress }); const exists = code !== undefined && code !== '0x'; return { exists, address: proxyAddress }; } ### 1.2 Create Proxy Wallet[](https://developer.probable.markets/api/orderbook-complete-guide#12-create-proxy-wallet) If the proxy doesn't exist, create it with an EIP-712 signature: import { PROXY_FACTORY_ABI } from './config'; async function createProxyWallet( userAddress: `0x${string}`, walletClient: WalletClient ): Promise<`0x${string}`> { const proxyFactory = getContract({ address: PROXY_FACTORY_ADDRESS, abi: PROXY_FACTORY_ABI, client: { public: publicClient, wallet: walletClient }, }); // Get computed proxy address const proxyAddress = await proxyFactory.read.computeProxyAddress([userAddress]); // Generate EIP-712 signature for CreateProxy const paymentToken = '0x0000000000000000000000000000000000000000'; const payment = 0n; const paymentReceiver = '0x0000000000000000000000000000000000000000'; const domain = { name: 'Probable Contract Proxy Factory', chainId: 56, verifyingContract: PROXY_FACTORY_ADDRESS, }; const types = { CreateProxy: [\ { name: 'paymentToken', type: 'address' },\ { name: 'payment', type: 'uint256' },\ { name: 'paymentReceiver', type: 'address' },\ ], }; const message = { paymentToken, payment, paymentReceiver }; const signature = await walletClient.signTypedData({ domain, types, primaryType: 'CreateProxy', message, }); // Parse signature into v, r, s const r = `0x${signature.slice(2, 66)}` as `0x${string}`; const s = `0x${signature.slice(66, 130)}` as `0x${string}`; let v = parseInt(signature.slice(130, 132), 16); if (v < 27) v += 27; // Create proxy const hash = await proxyFactory.write.createProxy( [paymentToken, payment, paymentReceiver, { v, r, s }], { account: walletClient.account } ); await publicClient.waitForTransactionReceipt({ hash }); return proxyAddress; } * * * Step 2: Approve Tokens[](https://developer.probable.markets/api/orderbook-complete-guide#step-2-approve-tokens) ------------------------------------------------------------------------------------------------------------------ Before placing orders, you must approve token spending. The proxy wallet needs three approvals: 1. **USDT → CTF Token Contract** (for splitting/merging positions) 2. **USDT → CTF Exchange** (for trading) 3. **CTF Tokens → CTF Exchange** (for trading) ### 2.1 Check Existing Approvals[](https://developer.probable.markets/api/orderbook-complete-guide#21-check-existing-approvals) import { maxUint256 } from 'viem'; import { ERC20_ABI, ERC1155_ABI } from './config'; async function checkApprovals(proxyAddress: `0x${string}`) { const [usdtForCTFToken, usdtForExchange, ctfTokenForExchange] = await publicClient.multicall({ contracts: [\ {\ address: USDT_ADDRESS,\ abi: ERC20_ABI,\ functionName: 'allowance',\ args: [proxyAddress, CTF_TOKEN_ADDRESS],\ },\ {\ address: USDT_ADDRESS,\ abi: ERC20_ABI,\ functionName: 'allowance',\ args: [proxyAddress, CTF_EXCHANGE_ADDRESS],\ },\ {\ address: CTF_TOKEN_ADDRESS,\ abi: ERC1155_ABI,\ functionName: 'isApprovedForAll',\ args: [proxyAddress, CTF_EXCHANGE_ADDRESS],\ },\ ], }); return { needsUSDTForCTFToken: usdtForCTFToken.result < maxUint256, needsUSDTForExchange: usdtForExchange.result < maxUint256, needsCTFTokenForExchange: !ctfTokenForExchange.result, }; } ### 2.2 Execute Approvals via Safe[](https://developer.probable.markets/api/orderbook-complete-guide#22-execute-approvals-via-safe) All approvals are executed through the proxy wallet (Gnosis Safe) in a single batch transaction: import Safe from '@safe-global/protocol-kit'; import { encodeFunctionData } from 'viem'; async function approveTokens( proxyAddress: `0x${string}`, privateKey: `0x${string}` ) { const protocolKit = await Safe.init({ provider: rpcUrl, signer: privateKey, safeAddress: proxyAddress, }); const transactions = []; // USDT approval for CTF Token transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: ERC20_ABI, functionName: 'approve', args: [CTF_TOKEN_ADDRESS, maxUint256], }) as `0x${string}`, value: '0', }); // USDT approval for Exchange transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: ERC20_ABI, functionName: 'approve', args: [CTF_EXCHANGE_ADDRESS, maxUint256], }) as `0x${string}`, value: '0', }); // CTF Token approval for Exchange transactions.push({ to: CTF_TOKEN_ADDRESS, data: encodeFunctionData({ abi: ERC1155_ABI, functionName: 'setApprovalForAll', args: [CTF_EXCHANGE_ADDRESS, true], }) as `0x${string}`, value: '0', }); const safeTransaction = await protocolKit.createTransaction({ transactions, }); const executeTxResponse = await protocolKit.executeTransaction(safeTransaction); await publicClient.waitForTransactionReceipt({ hash: executeTxResponse.hash }); } * * * Step 3: Deposit USDT to Proxy Wallet[](https://developer.probable.markets/api/orderbook-complete-guide#step-3-deposit-usdt-to-proxy-wallet) ---------------------------------------------------------------------------------------------------------------------------------------------- After approvals, deposit USDT from your EOA to the proxy wallet: async function depositUSDT( eoaAddress: `0x${string}`, proxyAddress: `0x${string}`, amount: bigint, walletClient: WalletClient ) { const hash = await walletClient.sendTransaction({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: ERC20_ABI, functionName: 'transfer', args: [proxyAddress, amount], }), account: walletClient.account, }); await publicClient.waitForTransactionReceipt({ hash }); } * * * Step 4: Create API Key[](https://developer.probable.markets/api/orderbook-complete-guide#step-4-create-api-key) ------------------------------------------------------------------------------------------------------------------ API keys are required for authenticated requests. They're created using L1 authentication (EIP-712 signature). ### 4.1 Build L1 Authentication Signature[](https://developer.probable.markets/api/orderbook-complete-guide#41-build-l1-authentication-signature) async function buildL1Signature( walletClient: WalletClient, chainId: number, timestamp: number, nonce: number ): Promise { const eoaAddress = walletClient.account.address; const MSG_TO_SIGN = "This message attests that I control the given wallet"; const domain = { name: 'ClobAuthDomain', version: '1', chainId: chainId, }; const types = { ClobAuth: [\ { name: 'address', type: 'address' },\ { name: 'timestamp', type: 'string' },\ { name: 'nonce', type: 'uint256' },\ { name: 'message', type: 'string' },\ ], }; const message = { address: eoaAddress, timestamp: timestamp.toString(), nonce: nonce, message: MSG_TO_SIGN, }; return await walletClient.signTypedData({ domain, types, primaryType: 'ClobAuth', message, }); } ### 4.2 Get Nonce and Create API Key[](https://developer.probable.markets/api/orderbook-complete-guide#42-get-nonce-and-create-api-key) import axios from 'axios'; async function createApiKey(walletClient: WalletClient): Promise<{ key: string; secret: string; passphrase: string; }> { const eoaAddress = walletClient.account.address; const timestamp = Math.floor(Date.now() / 1000); // Get nonce (optional, can use 0) const nonce = 0; // Build signature const signature = await buildL1Signature( walletClient, CHAIN_ID, timestamp, nonce ); // Create API key const response = await axios.post( `https://api.probable.markets/public/api/v1/auth/api-key/${CHAIN_ID}`, {}, { headers: { prob_address: eoaAddress, prob_signature: signature, prob_timestamp: timestamp.toString(), prob_nonce: nonce.toString(), }, } ); return { key: response.data.apiKey, secret: response.data.secret, passphrase: response.data.passphrase, }; } > **Important:** Store the `secret` and `passphrase` securely. They cannot be retrieved later. * * * Step 5: Create and Sign Order[](https://developer.probable.markets/api/orderbook-complete-guide#step-5-create-and-sign-order) -------------------------------------------------------------------------------------------------------------------------------- Orders are created using EIP-712 typed data signing. The order structure includes maker (proxy wallet), signer (EOA), token ID, amounts, and other parameters. ### 5.1 Build Order Data[](https://developer.probable.markets/api/orderbook-complete-guide#51-build-order-data) import { parseUnits } from 'viem'; interface UserOrder { tokenID: string; price: number; size: number; side: 0 | 1; // 0 = BUY, 1 = SELL feeRateBps?: number; // Max taker fee in basis points (175-1000) nonce?: number; } // Helper functions for rounding function roundDown(num: number, decimals: number): number { if (decimalPlaces(num) <= decimals) return num; return Math.floor(num * 10 ** decimals) / 10 ** decimals; } function roundUp(num: number, decimals: number): number { if (decimalPlaces(num) <= decimals) return num; return Math.ceil(num * 10 ** decimals) / 10 ** decimals; } function roundNormal(num: number, decimals: number): number { if (decimalPlaces(num) <= decimals) return num; return Math.round((num + Number.EPSILON) * 10 ** decimals) / 10 ** decimals; } function decimalPlaces(num: number): number { if (Number.isInteger(num)) return 0; const arr = num.toString().split('.'); if (arr.length <= 1) return 0; return arr[1]!.length; } // Rounding config based on tick size const ROUNDING_CONFIG = { '0.1': { price: 1, size: 2, amount: 3 }, '0.01': { price: 2, size: 2, amount: 4 }, '0.001': { price: 3, size: 2, amount: 5 }, '0.0001': { price: 4, size: 2, amount: 6 }, }; function calculateOrderAmounts( side: 0 | 1, size: number, price: number, tickSize: '0.01' | '0.1' | '0.001' | '0.0001' ): { rawMakerAmt: number; rawTakerAmt: number } { const roundConfig = ROUNDING_CONFIG[tickSize]; const rawPrice = roundNormal(price, roundConfig.price); if (side === 0) { // BUY const rawTakerAmt = roundDown(size, roundConfig.size); let rawMakerAmt = rawTakerAmt * rawPrice; if (decimalPlaces(rawMakerAmt) > roundConfig.amount) { rawMakerAmt = roundUp(rawMakerAmt, roundConfig.amount + 4); if (decimalPlaces(rawMakerAmt) > roundConfig.amount) { rawMakerAmt = roundDown(rawMakerAmt, roundConfig.amount); } } return { rawMakerAmt, rawTakerAmt }; } else { // SELL const rawMakerAmt = roundDown(size, roundConfig.size); let rawTakerAmt = rawMakerAmt * rawPrice; if (decimalPlaces(rawTakerAmt) > roundConfig.amount) { rawTakerAmt = roundUp(rawTakerAmt, roundConfig.amount + 4); if (decimalPlaces(rawTakerAmt) > roundConfig.amount) { rawTakerAmt = roundDown(rawTakerAmt, roundConfig.amount); } } return { rawMakerAmt, rawTakerAmt }; } } function buildOrderData( userOrder: UserOrder, eoaAddress: string, proxyAddress: string, tickSize: '0.01' | '0.1' | '0.001' | '0.0001' ): { maker: string; signer: string; tokenId: string; makerAmount: string; takerAmount: string; side: number; feeRateBps: string; nonce: string; expiration: string; signatureType: number; } { // Calculate raw amounts based on side const { rawMakerAmt, rawTakerAmt } = calculateOrderAmounts( userOrder.side, userOrder.size, userOrder.price, tickSize ); const makerAmount = parseUnits( rawMakerAmt.toString(), 18 // USDT decimals ).toString(); const takerAmount = parseUnits( rawTakerAmt.toString(), 18 ).toString(); const feeRateBps = userOrder.feeRateBps ?? 175; if (feeRateBps < 175 || feeRateBps > 1000) { throw new Error('feeRateBps must be between 175 and 1000 (inclusive)'); } return { maker: proxyAddress, // Use proxy wallet as maker signer: eoaAddress, // Use EOA as signer tokenId: userOrder.tokenID, makerAmount, takerAmount, side: userOrder.side, feeRateBps: feeRateBps.toString(), nonce: (userOrder.nonce || 0).toString(), expiration: '0', // 0 = no expiration signatureType: 1, // PROB_GNOSIS_SAFE }; } ### 5.2 Sign Order with EIP-712[](https://developer.probable.markets/api/orderbook-complete-guide#52-sign-order-with-eip-712) async function signOrder( orderData: ReturnType, walletClient: WalletClient, salt: string ): Promise { const domain = { name: 'Probable CTF Exchange', version: '1', chainId: CHAIN_ID, verifyingContract: CTF_EXCHANGE_ADDRESS, }; const types = { Order: [\ { name: 'salt', type: 'uint256' },\ { name: 'maker', type: 'address' },\ { name: 'signer', type: 'address' },\ { name: 'taker', type: 'address' },\ { name: 'tokenId', type: 'uint256' },\ { name: 'makerAmount', type: 'uint256' },\ { name: 'takerAmount', type: 'uint256' },\ { name: 'expiration', type: 'uint256' },\ { name: 'nonce', type: 'uint256' },\ { name: 'feeRateBps', type: 'uint256' },\ { name: 'side', type: 'uint8' },\ { name: 'signatureType', type: 'uint8' },\ ], }; const taker = '0x0000000000000000000000000000000000000000'; const message = { salt: BigInt(salt), maker: orderData.maker as `0x${string}`, signer: orderData.signer as `0x${string}`, taker: taker as `0x${string}`, tokenId: BigInt(orderData.tokenId), makerAmount: BigInt(orderData.makerAmount), takerAmount: BigInt(orderData.takerAmount), expiration: BigInt(orderData.expiration), nonce: BigInt(orderData.nonce), feeRateBps: BigInt(orderData.feeRateBps), side: orderData.side, signatureType: orderData.signatureType, }; return await walletClient.signTypedData({ domain, types, primaryType: 'Order', message, }); } * * * Step 6: Submit Order to API[](https://developer.probable.markets/api/orderbook-complete-guide#step-6-submit-order-to-api) ---------------------------------------------------------------------------------------------------------------------------- Finally, submit the signed order to the API using L2 authentication (HMAC signature). ### 6.1 Build L2 HMAC Signature[](https://developer.probable.markets/api/orderbook-complete-guide#61-build-l2-hmac-signature) import * as crypto from 'crypto'; function buildL2Signature( secret: string, timestamp: number, method: string, path: string, body: string ): string { const message = `${timestamp}${method}${path}${body}`; const base64Secret = Buffer.from(secret, 'base64'); const hmac = crypto.createHmac('sha256', base64Secret); const sig = hmac.update(message).digest('base64'); // URL-safe base64 encoding return sig.replace(/\+/g, '-').replace(/\//g, '_'); } ### 6.2 Submit Order[](https://developer.probable.markets/api/orderbook-complete-guide#62-submit-order) async function submitOrder( signedOrder: { salt: string; maker: string; signer: string; taker: string; tokenId: string; makerAmount: string; takerAmount: string; side: number; expiration: string; nonce: string; feeRateBps: string; signatureType: number; signature: string; }, apiKey: string, secret: string, passphrase: string, eoaAddress: string ) { const requestBody = { deferExec: true, order: { salt: signedOrder.salt, maker: signedOrder.maker, signer: signedOrder.signer, taker: signedOrder.taker, tokenId: signedOrder.tokenId, makerAmount: signedOrder.makerAmount, takerAmount: signedOrder.takerAmount, side: signedOrder.side === 0 ? 'BUY' : 'SELL', expiration: signedOrder.expiration, nonce: signedOrder.nonce, feeRateBps: signedOrder.feeRateBps, signatureType: signedOrder.signatureType, signature: signedOrder.signature, }, owner: signedOrder.maker, // Proxy wallet address orderType: 'GTC', // Good Till Cancel }; const timestamp = Math.floor(Date.now() / 1000); const method = 'POST'; const path = `/public/api/v1/order/${CHAIN_ID}`; const bodyString = JSON.stringify(requestBody); const signature = buildL2Signature(secret, timestamp, method, path, bodyString); const response = await axios.post( `https://api.probable.markets${path}`, requestBody, { headers: { 'Content-Type': 'application/json', prob_address: eoaAddress, // Use EOA address for authentication prob_signature: signature, prob_timestamp: timestamp.toString(), prob_api_key: apiKey, prob_passphrase: passphrase, }, } ); return response.data; } * * * Complete Example[](https://developer.probable.markets/api/orderbook-complete-guide#complete-example) ------------------------------------------------------------------------------------------------------- Here's a complete example that ties everything together: async function placeOrderFromEOA( walletClient: WalletClient, tokenId: string, price: number, size: number, side: 0 | 1 ) { const eoaAddress = walletClient.account.address; // Step 1: Create or get proxy wallet const { exists, address: proxyAddress } = await checkProxyExists(eoaAddress); if (!exists) { await createProxyWallet(eoaAddress, walletClient); } // Step 2: Approve tokens const approvals = await checkApprovals(proxyAddress); if (approvals.needsUSDTForCTFToken || approvals.needsUSDTForExchange || approvals.needsCTFTokenForExchange) { await approveTokens(proxyAddress, privateKey); } // Step 3: Ensure USDT balance (user should deposit manually) // Check balance and prompt user if needed // Step 4: Create API key const apiKey = await createApiKey(walletClient); // Step 5: Create and sign order const userOrder: UserOrder = { tokenID: tokenId, price, size, side, feeRateBps: 175, nonce: 0, }; const orderData = buildOrderData(userOrder, eoaAddress, proxyAddress, '0.01'); const salt = `${Math.round(Math.random() * Date.now())}`; const signature = await signOrder(orderData, walletClient, salt); const signedOrder = { ...orderData, salt, taker: '0x0000000000000000000000000000000000000000', signature, }; // Step 6: Submit order const result = await submitOrder( signedOrder, apiKey.key, apiKey.secret, apiKey.passphrase, eoaAddress ); console.log('Order placed:', result); return result; } * * * Key Points to Remember[](https://developer.probable.markets/api/orderbook-complete-guide#key-points-to-remember) ------------------------------------------------------------------------------------------------------------------- 1. **Address Usage:** * **Authentication headers (`prob_address`)**: Always use your **EOA address** * **Order `maker` field**: Use your **proxy wallet address** * **Order `signer` field**: Use your **EOA address** (signs the order) * **Order `owner` field**: Use your **proxy wallet address** 2. **Signature Types:** * L1 authentication: EIP-712 signature with EOA * Order signing: EIP-712 signature with EOA (signatureType = 1 for PROB\_GNOSIS\_SAFE) * L2 API requests: HMAC-SHA256 signature with API secret 3. **Token Approvals:** * All approvals are executed through the proxy wallet (Gnosis Safe) * Approvals can be batched in a single Safe transaction 4. **Order Parameters:** * `tickSize`: Determines price precision ('0.01', '0.1', '0.001', or '0.0001') * `deferExec`: Set to `true` to defer execution * `feeRateBps`: Max taker fee in basis points (175-1000) * `orderType`: 'GTC' (Good Till Cancel) or 'IOC' (Immediate Or Cancel) * * * Next Steps[](https://developer.probable.markets/api/orderbook-complete-guide#next-steps) ------------------------------------------------------------------------------------------- * [Orderbook API Overview](https://developer.probable.markets/api/orderbook-api/overview) - Complete API reference * [Orders API](https://developer.probable.markets/api/orderbook-api/orders) - Order management endpoints * [Proxy Wallet Guide](https://developer.probable.markets/api/orderbook-api/proxy-wallet) - Detailed proxy wallet documentation * [Authentication Guide](https://developer.probable.markets/api/orderbook-api/authentication) - Authentication details --- # Overview | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/overview#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Overview On this page Chevron Right The Probable Markets TypeScript SDK (`@prob/clob`) provides a convenient way to interact with Probable’s prediction market APIs, including order placement, market data, positions, and authenticated endpoints. Packages[](https://developer.probable.markets/api/typescript-sdk/overview#packages) -------------------------------------------------------------------------------------- The SDK is published as a monorepo with three main packages: * `@prob/clob` — main client for CLOB + market APIs * `@prob/core` — core utilities (exchange configs, ABIs, token ops) * `@prob/types` — shared TypeScript types What you can build[](https://developer.probable.markets/api/typescript-sdk/overview#what-you-can-build) ---------------------------------------------------------------------------------------------------------- * Place and manage orders (limit/market, cancel, open orders) * Query markets/events, orderbooks, prices, and price history * Query and manage positions (split/merge/redeem) * Use authenticated endpoints (L1 wallet signature + L2 API key) * Subscribe to stream data over WebSocket Next steps[](https://developer.probable.markets/api/typescript-sdk/overview#next-steps) ------------------------------------------------------------------------------------------ * [Installation](https://developer.probable.markets/api/typescript-sdk/installation) * [Quick Start](https://developer.probable.markets/api/typescript-sdk/quickstart) * [Orders](https://developer.probable.markets/api/typescript-sdk/orders) * [Fees](https://developer.probable.markets/api/typescript-sdk/fees) * [Market Data](https://developer.probable.markets/api/typescript-sdk/market-data) * [Positions](https://developer.probable.markets/api/typescript-sdk/positions) * [WebSocket](https://developer.probable.markets/api/typescript-sdk/websocket) * [Proxy Wallet](https://developer.probable.markets/api/typescript-sdk/proxy-wallet) --- # Installation | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/installation#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Installation On this page Chevron Right Install the SDK in your project: # pnpm pnpm add @prob/clob # npm npm install @prob/clob # yarn yarn add @prob/clob Imports[](https://developer.probable.markets/api/typescript-sdk/installation#imports) ---------------------------------------------------------------------------------------- Most examples use: import { createClobClient } from "@prob/clob"; --- # Orders | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/orders#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Orders On this page Chevron Right Create and submit a limit order[](https://developer.probable.markets/api/typescript-sdk/orders#create-and-submit-a-limit-order) ---------------------------------------------------------------------------------------------------------------------------------- import { LimitTimeInForce, OrderSide } from "@prob/clob"; const order = await client.createLimitOrder({ tokenId: "...", price: 0.6, size: 100, side: OrderSide.Buy, timeInForce: LimitTimeInForce.GTC, }); // Optional: override feeRateBps (max taker fee), in basis points. // Must be between 175 and 1000 (inclusive). The SDK uses bigint here. order.feeRateBps = 175n; const { orderId } = await client.postOrder(order); Create and submit a market order[](https://developer.probable.markets/api/typescript-sdk/orders#create-and-submit-a-market-order) ------------------------------------------------------------------------------------------------------------------------------------ const marketOrder = await client.createMarketOrder({ tokenId: "...", size: 100, side: OrderSide.Buy, }); // Optional: override feeRateBps (max taker fee), in basis points. // Must be between 175 and 1000 (inclusive). The SDK uses bigint here. marketOrder.feeRateBps = 175n; const feeAmount = calculateFee(marketOrder) await client.postOrder(marketOrder); Read and cancel orders[](https://developer.probable.markets/api/typescript-sdk/orders#read-and-cancel-orders) ---------------------------------------------------------------------------------------------------------------- const openOrders = await client.getOpenOrders({ eventId: "162" }); await client.cancelAllOrders({ eventId: "162" }); --- # Fees | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/fees#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Fees On this page Chevron Right Please read the [Fees](https://docs.probable.markets/trade-on-probable/fees) page for more information about fees calculation. Fees Calculation[](https://developer.probable.markets/api/typescript-sdk/fees#fees-calculation) -------------------------------------------------------------------------------------------------- import { calculateFee } from '@prob/clob' const order = await client.createLimitOrder({...}) // // or // const order = await client.createMarketOrder({...}) const feeAmount = calculateFee(order) --- # Quick Start | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/quickstart#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Quick Start On this page Chevron Right Create a wallet client, then create the CLOB client. For authenticated methods, generate an API key once per client (it will be stored in the client instance). import { createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { bscTestnet } from "viem/chains"; import { createClobClient } from "@prob/clob"; const account = privateKeyToAccount("0x..." as `0x${string}`); const wallet = createWalletClient({ chain: bscTestnet, transport: http(), account, }); const client = createClobClient({ baseUrl: "https://api.probable.markets/public/api/v1", chainId: bscTestnet.id, wallet, }); await client.generateApiKey(); Basic usage (public)[](https://developer.probable.markets/api/typescript-sdk/quickstart#basic-usage-public) -------------------------------------------------------------------------------------------------------------- const markets = await client.getMarkets({ eventId: "162" }); const orderbook = await client.getOrderBook({ tokenId: "..." }); Basic usage (authenticated)[](https://developer.probable.markets/api/typescript-sdk/quickstart#basic-usage-authenticated) ---------------------------------------------------------------------------------------------------------------------------- const positions = await client.getCurrentPositions({ eventId: "162" }); --- # Market Data | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/market-data#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Market Data On this page Chevron Right Events and markets[](https://developer.probable.markets/api/typescript-sdk/market-data#events-and-markets) ------------------------------------------------------------------------------------------------------------- const events = await client.getEvents({ limit: 10 }); const markets = await client.getMarkets({ eventId: "162" }); Search[](https://developer.probable.markets/api/typescript-sdk/market-data#search) ------------------------------------------------------------------------------------- const results = await client.search({ query: "bitcoin" }); Orderbook and prices[](https://developer.probable.markets/api/typescript-sdk/market-data#orderbook-and-prices) ----------------------------------------------------------------------------------------------------------------- const orderbook = await client.getOrderBook({ tokenId: "..." }); const price = await client.getPrice({ tokenId: "..." }); const prices = await client.getPrices({ tokenIds: ["...", "..."] }); const priceHistory = await client.getPricesHistory({ tokenId: "...", startTime: Date.now() - 86_400_000, endTime: Date.now(), }); Trade history[](https://developer.probable.markets/api/typescript-sdk/market-data#trade-history) --------------------------------------------------------------------------------------------------- const activity = await client.getActivity({ eventId: "162" }); const pnl = await client.getPnL({ eventId: "162" }); const trades = await client.getTrades({ eventId: "162" }); --- # Proxy Wallet | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/proxy-wallet#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Proxy Wallet On this page Chevron Right The SDK includes helpers for Safe proxy wallet operations. Check if a proxy wallet exists[](https://developer.probable.markets/api/typescript-sdk/proxy-wallet#check-if-a-proxy-wallet-exists) -------------------------------------------------------------------------------------------------------------------------------------- const exists = await client.checkSafeProxyWalletExists(); Approve collateral[](https://developer.probable.markets/api/typescript-sdk/proxy-wallet#approve-collateral) -------------------------------------------------------------------------------------------------------------- await client.proxyApproveCollateralIfNeeded(); await client.proxyApproveCollateral(BigInt(1000e6)); Execute a transaction via proxy[](https://developer.probable.markets/api/typescript-sdk/proxy-wallet#execute-a-transaction-via-proxy) ---------------------------------------------------------------------------------------------------------------------------------------- const txHash = await client.proxyExecuteTx({ to: "0x...", data: "0x...", value: BigInt(0), }); --- # Positions | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/positions#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Positions On this page Chevron Right Query positions[](https://developer.probable.markets/api/typescript-sdk/positions#query-positions) ----------------------------------------------------------------------------------------------------- const current = await client.getCurrentPositions({ eventId: "162" }); const closed = await client.getClosedPositions({ eventId: "162" }); const pending = await client.getPendingPositions({ eventId: "162" }); const value = await client.getPositionValue({ eventId: "162" }); Split, merge, redeem[](https://developer.probable.markets/api/typescript-sdk/positions#split-merge-redeem) ------------------------------------------------------------------------------------------------------------- const conditionId = "0x..." as const; await client.splitPosition({ conditionId, formattedAmount: "1" }); await client.mergePosition({ conditionId, formattedAmount: "1" }); await client.redeemPosition({ conditionId }); --- # Search API | Probable Developer [Skip to content](https://developer.probable.markets/api/market-public/search#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Search On this page Chevron Right Full-text search across events and markets with comprehensive filtering, sorting, and caching options. Search Events and Markets[](https://developer.probable.markets/api/market-public/search#search-events-and-markets) --------------------------------------------------------------------------------------------------------------------- Search across event titles, market questions, and tags with advanced filtering capabilities. **Endpoint:** `GET /public/api/v1/public-search/` ### Query Parameters[](https://developer.probable.markets/api/market-public/search#query-parameters) #### Search (Required)[](https://developer.probable.markets/api/market-public/search#search-required) * `q` (string, required) - Search query text - searches event titles, market questions, and tags #### Pagination (Optional)[](https://developer.probable.markets/api/market-public/search#pagination-optional) * `page` (integer, default: 1) - Page number using 1-based indexing * `limit` (integer, default: 20, max: 100) - Results per page * `cache` (boolean, default: false) - Use Redis cache for 3 minutes #### Event Filtering (Optional)[](https://developer.probable.markets/api/market-public/search#event-filtering-optional) * `events_status` (string, default: all) - Filter by `active`, `closed`, or `all` * `events_tag` (string or array) - Filter by event type/category (e.g., crypto, sports, politics) * `recurrence` (string) - Filter by market structure: `single`, `daily`, `weekly`, `monthly` * `exclude_tag_id` (integer or array) - Exclude specific category IDs #### Market Filtering (Optional)[](https://developer.probable.markets/api/market-public/search#market-filtering-optional) * `keep_closed_markets` (0 or 1, default: 1) - Include (1) or exclude (0) closed markets #### Sorting (Optional)[](https://developer.probable.markets/api/market-public/search#sorting-optional) * `sort` (string, default: relevance) - Sort by `relevance`, `volume`, `created_at`, or `end_date` * `ascending` (boolean, default: false) - Sort ascending instead of descending #### Advanced (Optional)[](https://developer.probable.markets/api/market-public/search#advanced-optional) * `search_tags` (boolean, default: true) - Include event types/categories in search * `optimized` (boolean, default: false) - Return lightweight response without nested markets ### Example Requests[](https://developer.probable.markets/api/market-public/search#example-requests) #### Basic Search[](https://developer.probable.markets/api/market-public/search#basic-search) curl "https://market-api.probable.markets/public/api/v1/public-search/?q=bitcoin" #### Filtered Search[](https://developer.probable.markets/api/market-public/search#filtered-search) curl "https://market-api.probable.markets/public/api/v1/public-search/?q=ethereum&events_tag=crypto&events_status=active" #### Sorted Search[](https://developer.probable.markets/api/market-public/search#sorted-search) curl "https://market-api.probable.markets/public/api/v1/public-search/?q=ai&sort=created_at&ascending=true" #### Cached Search[](https://developer.probable.markets/api/market-public/search#cached-search) curl "https://market-api.probable.markets/public/api/v1/public-search/?q=trump&cache=true" #### Lightweight Search[](https://developer.probable.markets/api/market-public/search#lightweight-search) curl "https://market-api.probable.markets/public/api/v1/public-search/?q=sports&optimized=true" ### Example Response[](https://developer.probable.markets/api/market-public/search#example-response) { "events": [\ {\ "id": 123,\ "slug": "btc-usd-2025-11",\ "title": "Bitcoin Price Prediction",\ "markets": [\ {\ "id": 456,\ "question": "Will BTC exceed $100k?",\ "market_slug": "btc-100k"\ }\ ]\ }\ ], "tags": [\ {\ "id": 1,\ "label": "Crypto",\ "slug": "crypto"\ }\ ], "pagination": { "hasMore": true, "totalResults": 50, "page": 1, "limit": 20, "totalPages": 3, "hasPrevPage": false } } ### Optimized Response[](https://developer.probable.markets/api/market-public/search#optimized-response) When `optimized=true`, the response excludes nested markets: { "events": [\ {\ "id": 123,\ "slug": "btc-usd-2025-11",\ "title": "Bitcoin Price Prediction"\ // markets array is empty\ }\ ], "tags": [...], "pagination": {...} } ### Caching[](https://developer.probable.markets/api/market-public/search#caching) * Results cached for 3 minutes when `cache=true` * Cache key includes all search parameters * Use caching for frequently repeated searches ### Use Cases[](https://developer.probable.markets/api/market-public/search#use-cases) * **Frontend Search Bars**: Real-time search as users type * **Category Browsing**: Filter by tags and status * **Trending Markets**: Sort by volume or creation date * **Archived Content**: Include or exclude closed markets --- # WebSocket | Probable Developer [Skip to content](https://developer.probable.markets/api/typescript-sdk/websocket#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu WebSocket On this page Chevron Right Create a client with `wsUrl`, generate an API key, then subscribe. const client = createClobClient({ baseUrl: "https://api.probable.markets/public/api/v1", wsUrl: "wss://ws.probable.markets/public/api/v1", chainId: 56, wallet, }); await client.generateApiKey(); const sub = client.subscribeStreamData("executionReport", (data) => { console.log("Order ID:", data.i); }); sub.on("ready", (data) => console.log("ready", data?.listenKey)); sub.on("error", (err) => console.error(err)); sub.on("close", () => console.log("closed")); --- # Tags API | Probable Developer [Skip to content](https://developer.probable.markets/api/market-public/tags#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Tags On this page Chevron Right Endpoints for retrieving and managing tags used to categorize events and markets. List All Tags[](https://developer.probable.markets/api/market-public/tags#list-all-tags) ------------------------------------------------------------------------------------------- Get a paginated list of all tags available in the system. **Endpoint:** `GET /public/api/v1/tags/` ### Query Parameters[](https://developer.probable.markets/api/market-public/tags#query-parameters) All parameters are optional. * `page` (integer, default: 1) - Page number using 1-based indexing * `limit` (integer, default: 20, max: 100) - Results per page * `sort` (string, default: label) - Sort by field: `label`, `slug`, or `id` * `order` (string, default: asc) - Sort order: `asc` or `desc` ### Example Request[](https://developer.probable.markets/api/market-public/tags#example-request) curl "https://market-api.probable.markets/public/api/v1/tags/?page=1&limit=20&sort=label&order=asc" ### Example Response[](https://developer.probable.markets/api/market-public/tags#example-response) { "tags": [\ {\ "id": 1,\ "label": "Sports",\ "slug": "sports"\ },\ {\ "id": 2,\ "label": "Crypto",\ "slug": "crypto"\ },\ {\ "id": 3,\ "label": "Politics",\ "slug": "politics"\ }\ ], "pagination": { "page": 1, "limit": 20, "totalResults": 150, "totalPages": 8, "hasMore": true, "hasPrevPage": false } } ### Use Case[](https://developer.probable.markets/api/market-public/tags#use-case) Frontend can use this endpoint to populate tag selection dropdowns when creating events/markets or filtering content. ### Caching[](https://developer.probable.markets/api/market-public/tags#caching) Results are cached for 5 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/tags#error-responses) * `500` - Internal server error --- # Markets API | Probable Developer [Skip to content](https://developer.probable.markets/api/market-public/markets#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Markets On this page Chevron Right Endpoints for retrieving prediction market information. List All Markets[](https://developer.probable.markets/api/market-public/markets#list-all-markets) ---------------------------------------------------------------------------------------------------- Get a paginated list of prediction markets with comprehensive filtering options. **Endpoint:** `GET /public/api/v1/markets/` ### Query Parameters[](https://developer.probable.markets/api/market-public/markets#query-parameters) All parameters are optional. #### Pagination[](https://developer.probable.markets/api/market-public/markets#pagination) * `page` (integer, default: 1) - Page number using 1-based indexing * `limit` (integer, default: 20, max: 100) - Results per page * `offset` (integer) - Results to skip (0-based). Use instead of page for offset-based pagination #### Filtering[](https://developer.probable.markets/api/market-public/markets#filtering) * `status` (string) - Filter by market status (e.g., "new", "processing", "completed") * `active` (boolean) - Only active markets if true * `closed` (boolean) - Only closed markets if true * `event_id` (integer) - Filter by event ID ### Example Request[](https://developer.probable.markets/api/market-public/markets#example-request) curl "https://market-api.probable.markets/public/api/v1/markets/?page=1&limit=20&active=true" ### Example Response[](https://developer.probable.markets/api/market-public/markets#example-response) { "markets": [\ {\ "id": 456,\ "condition_id": "0x123...",\ "question": "Will BTC exceed $100k?",\ "market_slug": "btc-100k",\ "outcomes": ["Yes", "No"],\ "clobTokenIds": ["0xabc...", "0xdef..."],\ "active": true,\ "closed": false\ }\ ], "pagination": { "hasMore": true, "totalResults": 500, "page": 1, "limit": 20, "totalPages": 25, "hasPrevPage": false } } ### Market Fields[](https://developer.probable.markets/api/market-public/markets#market-fields) * `id` - Market identifier * `condition_id` - CTF Conditional Token ID * `question` - Market question/title * `market_slug` - URL-friendly market identifier * `outcomes` - Array of outcome names * `clobTokenIds` - CTF token IDs for trading * `active` - Boolean market status * `closed` - Boolean closed status ### Caching[](https://developer.probable.markets/api/market-public/markets#caching) Results are cached for 3 minutes. * * * Get Market by ID[](https://developer.probable.markets/api/market-public/markets#get-market-by-id) ---------------------------------------------------------------------------------------------------- Retrieve detailed information for a single market by its numeric ID, including outcomes and associated event. **Endpoint:** `GET /public/api/v1/markets/{id}` ### Path Parameters[](https://developer.probable.markets/api/market-public/markets#path-parameters) * `id` (required, integer) - Numeric market identifier ### Example Request[](https://developer.probable.markets/api/market-public/markets#example-request-1) curl "https://market-api.probable.markets/public/api/v1/markets/456" ### Example Response[](https://developer.probable.markets/api/market-public/markets#example-response-1) { "id": 456, "condition_id": "0x123...", "question": "Will BTC exceed $100k?", "description": "Predict if Bitcoin will reach $100,000...", "market_slug": "btc-100k", "outcomes": ["Yes", "No"], "clobTokenIds": ["0xabc...", "0xdef..."], "active": true, "closed": false, "archived": false, "event": { "id": 123, "slug": "btc-usd-2025-11", "title": "Bitcoin Price Prediction" }, "volume": 500000, "liquidity": 100000 } ### Caching[](https://developer.probable.markets/api/market-public/markets#caching-1) Results are cached for 2 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/markets#error-responses) * `404` - Market not found with provided ID * `500` - Internal server error * * * Get Market by Polymarket ID[](https://developer.probable.markets/api/market-public/markets#get-market-by-polymarket-id) -------------------------------------------------------------------------------------------------------------------------- Retrieve market details using the Polymarket API identifier. Useful for cross-referencing with external Polymarket data. **Endpoint:** `GET /public/api/v1/markets/polymarket/{polymarketId}` ### Path Parameters[](https://developer.probable.markets/api/market-public/markets#path-parameters-1) * `polymarketId` (required, string) - Polymarket market identifier ### Example Request[](https://developer.probable.markets/api/market-public/markets#example-request-2) curl "https://market-api.probable.markets/public/api/v1/markets/polymarket/pm-market-123" ### Example Response[](https://developer.probable.markets/api/market-public/markets#example-response-2) Same structure as Get Market by ID. ### Caching[](https://developer.probable.markets/api/market-public/markets#caching-2) Results are cached for 2 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/markets#error-responses-1) * `404` - Market not found with provided Polymarket ID * `500` - Internal server error * * * Get Market by BSC Question ID[](https://developer.probable.markets/api/market-public/markets#get-market-by-bsc-question-id) ------------------------------------------------------------------------------------------------------------------------------ Retrieve market details using the BSC (Binance Smart Chain) question ID. Useful for on-chain cross-referencing. **Endpoint:** `GET /public/api/v1/markets/bsc/{bscQuestionId}` ### Path Parameters[](https://developer.probable.markets/api/market-public/markets#path-parameters-2) * `bscQuestionId` (required, string) - BSC question identifier ### Example Request[](https://developer.probable.markets/api/market-public/markets#example-request-3) curl "https://market-api.probable.markets/public/api/v1/markets/bsc/0xabc123..." ### Example Response[](https://developer.probable.markets/api/market-public/markets#example-response-3) Same structure as Get Market by ID. ### Caching[](https://developer.probable.markets/api/market-public/markets#caching-3) Results are cached for 2 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/markets#error-responses-2) * `404` - Market not found with provided BSC question ID * `500` - Internal server error --- # Events API | Probable Developer [Skip to content](https://developer.probable.markets/api/market-public/events#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Events On this page Chevron Right Endpoints for retrieving prediction market events. List All Events[](https://developer.probable.markets/api/market-public/events#list-all-events) ------------------------------------------------------------------------------------------------- Get a paginated list of prediction market events with comprehensive filtering and sorting options. **Endpoint:** `GET /public/api/v1/events/` ### Query Parameters[](https://developer.probable.markets/api/market-public/events#query-parameters) All parameters are optional. #### Pagination[](https://developer.probable.markets/api/market-public/events#pagination) * `page` (integer, default: 1) - Page number using 1-based indexing * `limit` (integer, default: 20, max: 100) - Results per page * `offset` (integer) - Results to skip (0-based). Use instead of page for offset-based pagination #### Filtering[](https://developer.probable.markets/api/market-public/events#filtering) * `status` (string) - Filter by status: `active`, `closed`, or `all` (default: all) * `closed` (boolean) - Only closed events if true, only open if false * `tag_id` (integer or array) - Filter by category tag ID(s) * `exclude_tag_id` (integer or array) - Exclude events with these tag IDs * `tag_slug` (string or array) - Filter by tag slug(s) * `active` (boolean) - Filter by active status * `recurrence` (string) - Filter by market structure: `daily`, `weekly`, or `monthly` * `related_tags` (boolean, default: false) - Include events with related tags * `start_date_min` (string) - Filter events starting after this date (ISO string) * `start_date_max` (string) - Filter events starting before this date (ISO string) * `end_date_min` (string) - Filter events ending after this date (ISO string) * `end_date_max` (string) - Filter events ending before this date (ISO string) #### Sorting[](https://developer.probable.markets/api/market-public/events#sorting) * `sort` (string) - Sort field: `created_at`, `volume`, or `market_count` (default: created\_at) * `order` (string) - Comma-separated list of fields to order by * `ascending` (boolean, default: false) - Sort ascending instead of descending ### Example Request[](https://developer.probable.markets/api/market-public/events#example-request) curl "https://market-api.probable.markets/public/api/v1/events/?page=1&limit=20&status=active&tag_id=1" ### Example Response[](https://developer.probable.markets/api/market-public/events#example-response) { "events": [\ {\ "id": 1,\ "slug": "btc-usd-2025-11",\ "title": "Bitcoin Price Prediction",\ "image": "https://...",\ "icon": "https://...",\ "status": "active",\ "markets": [...],\ "volume": 1000000,\ "market_count": 5\ }\ ], "pagination": { "hasMore": true, "totalResults": 150, "page": 1, "limit": 20, "totalPages": 8, "hasPrevPage": false } } ### Caching[](https://developer.probable.markets/api/market-public/events#caching) Results are cached for 5 minutes. Cache key includes all parameters. * * * Get Event by ID[](https://developer.probable.markets/api/market-public/events#get-event-by-id) ------------------------------------------------------------------------------------------------- Retrieve a complete event with all associated markets by its numeric ID. **Endpoint:** `GET /public/api/v1/events/{id}` ### Path Parameters[](https://developer.probable.markets/api/market-public/events#path-parameters) * `id` (required, integer) - Numeric event identifier ### Example Request[](https://developer.probable.markets/api/market-public/events#example-request-1) curl "https://market-api.probable.markets/public/api/v1/events/123" ### Example Response[](https://developer.probable.markets/api/market-public/events#example-response-1) { "id": 123, "slug": "btc-usd-2025-11", "title": "Bitcoin Price Prediction", "description": "Predict the price of Bitcoin...", "image": "https://...", "icon": "https://...", "status": "active", "markets": [\ {\ "id": 456,\ "question": "Will BTC exceed $100k?",\ "market_slug": "btc-100k",\ "outcomes": ["Yes", "No"],\ "active": true,\ "closed": false\ }\ ], "volume": 1000000, "market_count": 5 } ### Caching[](https://developer.probable.markets/api/market-public/events#caching-1) Results are cached for 2 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/events#error-responses) * `400` - Invalid or malformed event ID * `404` - Event not found * `500` - Internal server error * * * Get Event by Slug[](https://developer.probable.markets/api/market-public/events#get-event-by-slug) ----------------------------------------------------------------------------------------------------- Retrieve a complete event with all associated markets by its slug identifier. **Endpoint:** `GET /public/api/v1/events/slug/{slug}` ### Path Parameters[](https://developer.probable.markets/api/market-public/events#path-parameters-1) * `slug` (required, string) - URL-friendly event identifier (e.g., "btc-usd-2025-11") ### Example Request[](https://developer.probable.markets/api/market-public/events#example-request-2) curl "https://market-api.probable.markets/public/api/v1/events/slug/btc-usd-2025-11" ### Example Response[](https://developer.probable.markets/api/market-public/events#example-response-2) Same structure as Get Event by ID. ### Caching[](https://developer.probable.markets/api/market-public/events#caching-2) Results are cached for 2 minutes. ### Error Responses[](https://developer.probable.markets/api/market-public/events#error-responses-1) * `404` - Event not found with provided slug * `500` - Internal server error * * * Get Tags for Event[](https://developer.probable.markets/api/market-public/events#get-tags-for-event) ------------------------------------------------------------------------------------------------------- Retrieve all tags associated with an event by its ID. **Endpoint:** `GET /public/api/v1/events/{id}/tags` ### Path Parameters[](https://developer.probable.markets/api/market-public/events#path-parameters-2) * `id` (required, integer) - Numeric event identifier ### Example Request[](https://developer.probable.markets/api/market-public/events#example-request-3) curl "https://market-api.probable.markets/public/api/v1/events/123/tags" ### Example Response[](https://developer.probable.markets/api/market-public/events#example-response-3) [\ {\ "id": 1,\ "label": "Crypto",\ "slug": "crypto"\ },\ {\ "id": 2,\ "label": "Price Prediction",\ "slug": "price-prediction"\ }\ ] ### Notes[](https://developer.probable.markets/api/market-public/events#notes) * Returns an empty array if the event has no tags or if the event does not exist --- # API Keys API Reference | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/api-keys#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu API Keys On this page Chevron Right Complete reference documentation for API key management endpoints. > **Prerequisites:** API key generation requires L1 authentication. See the [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) > for the complete authentication flow. Generate API Key[](https://developer.probable.markets/api/orderbook-api/api-keys#generate-api-key) ----------------------------------------------------------------------------------------------------- Create a new API key for a specific chain. **Endpoint:** `POST /public/api/v1/auth/api-key/{chainId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/api-keys#path-parameters) * `chainId` (required, number) - Chain ID ### Headers (L1 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/api-keys#headers-l1-authentication-required) * `prob_address` - **EOA address** (Externally Owned Account address) * `prob_signature` - EIP-712 signature **signed by the EOA** * `prob_timestamp` - Unix timestamp * `prob_nonce` - Nonce from nonce endpoint ### Example Request[](https://developer.probable.markets/api/orderbook-api/api-keys#example-request) curl -X POST "https://api.probable.markets/public/api/v1/auth/api-key/56" \ -H "prob_address: 0x1234..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_nonce: abc123xyz" ### Example Response[](https://developer.probable.markets/api/orderbook-api/api-keys#example-response) { "apiKey": "pk_live_abc123xyz", "secret": "sk_live_def456uvw", "passphrase": "my-passphrase" } **Important:** Store the secret and passphrase securely. They cannot be retrieved later. * * * Get API Key[](https://developer.probable.markets/api/orderbook-api/api-keys#get-api-key) ------------------------------------------------------------------------------------------- Retrieve existing API key information. **Endpoint:** `GET /public/api/v1/auth/api-key/{chainId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/api-keys#path-parameters-1) * `chainId` (required, number) - Chain ID ### Headers (L1 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/api-keys#headers-l1-authentication-required-1) * `prob_address` - **EOA address** (same as used for API key generation) * `prob_signature` - EIP-712 signature **signed by the EOA** * `prob_timestamp` - Unix timestamp * `prob_nonce` - Nonce ### Example Request[](https://developer.probable.markets/api/orderbook-api/api-keys#example-request-1) curl "https://api.probable.markets/public/api/v1/auth/api-key/56" \ -H "prob_address: 0x1234..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_nonce: abc123xyz" ### Example Response[](https://developer.probable.markets/api/orderbook-api/api-keys#example-response-1) { "apiKey": "pk_live_abc123xyz", "secret": "sk_live_def456uvw", "passphrase": "my-passphrase" } * * * Delete API Key[](https://developer.probable.markets/api/orderbook-api/api-keys#delete-api-key) ------------------------------------------------------------------------------------------------- Delete an API key. **Endpoint:** `DELETE /public/api/v1/auth/api-key/{chainId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/api-keys#path-parameters-2) * `chainId` (required, number) - Chain ID ### Headers (L1 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/api-keys#headers-l1-authentication-required-2) * `prob_address` - **EOA address** (same as used for API key generation) * `prob_signature` - EIP-712 signature **signed by the EOA** * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key to delete * `prob_passphrase` - API passphrase ### Example Request[](https://developer.probable.markets/api/orderbook-api/api-keys#example-request-2) curl -X DELETE "https://api.probable.markets/public/api/v1/auth/api-key/56" \ -H "prob_address: 0x1234..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" ### Example Response[](https://developer.probable.markets/api/orderbook-api/api-keys#example-response-2) { "success": true, "message": "API key deleted successfully" } ### Security Notes[](https://developer.probable.markets/api/orderbook-api/api-keys#security-notes) * Deleting an API key immediately invalidates it * All requests using the deleted key will fail * Generate a new key if you need to continue using the API --- # Authentication API Reference | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/authentication#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Authentication On this page Chevron Right Complete reference documentation for authentication endpoints. > **New to authentication?** Start with the [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) > for a step-by-step walkthrough. Authentication Levels[](https://developer.probable.markets/api/orderbook-api/authentication#authentication-levels) --------------------------------------------------------------------------------------------------------------------- ### L1 Authentication (EIP-712)[](https://developer.probable.markets/api/orderbook-api/authentication#l1-authentication-eip-712) Used for initial authentication and API key generation. Requires wallet signature. **Headers Required:** * `prob_address` - **EOA address** (Externally Owned Account address) * `prob_signature` - EIP-712 signature **signed by the EOA** * `prob_timestamp` - Unix timestamp * `prob_nonce` - Nonce from `/public/api/v1/auth/nonce` > **Important:** `prob_address` must be your EOA address, and the signature must be signed by that EOA. ### L2 Authentication (HMAC)[](https://developer.probable.markets/api/orderbook-api/authentication#l2-authentication-hmac) Used for authenticated API requests, including all orderbook write operations. Requires API key and secret. **Headers Required:** * `prob_address` - **EOA address** (same as used in L1 authentication) * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase > **Important:** `prob_address` must be your EOA address (not proxy wallet address). Generate Nonce[](https://developer.probable.markets/api/orderbook-api/authentication#generate-nonce) ------------------------------------------------------------------------------------------------------- Get a nonce for L1 authentication. **Endpoint:** `GET /public/api/v1/auth/nonce` ### Example Request[](https://developer.probable.markets/api/orderbook-api/authentication#example-request) curl "https://api.probable.markets/public/api/v1/auth/nonce" ### Example Response[](https://developer.probable.markets/api/orderbook-api/authentication#example-response) { "nonce": "abc123xyz", "issuedAt": "2025-01-15T10:30:00Z" } Login[](https://developer.probable.markets/api/orderbook-api/authentication#login) ------------------------------------------------------------------------------------- Authenticate a user with wallet signature. **Endpoint:** `POST /public/api/v1/auth/login` ### Request Body[](https://developer.probable.markets/api/orderbook-api/authentication#request-body) { "identity": { "account": "0x1234...", "namespace": "default", "chainId": "56", "address": "0x1234..." }, "message": "Sign in to Prob...", "signature": "0xabc123...", "nonce": "abc123xyz", "issuedAt": "2025-01-15T10:30:00Z", "domain": "prob.vbgf.cc" } ### Parameters[](https://developer.probable.markets/api/orderbook-api/authentication#parameters) * `identity` (required, object) - User identity information * `account` (required, string) - Account address * `namespace` (required, string) - Namespace * `chainId` (required, string) - Chain ID * `address` (required, string) - Wallet address * `message` (required, string) - Login message * `signature` (required, string) - Wallet signature (0x-prefixed hex) * `nonce` (required, string) - Nonce from nonce endpoint * `issuedAt` (required, string) - ISO timestamp * `domain` (required, string) - Domain name ### Example Request[](https://developer.probable.markets/api/orderbook-api/authentication#example-request-1) curl -X POST "https://api.probable.markets/public/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d '{ "identity": { "account": "0x1234...", "namespace": "default", "chainId": "56", "address": "0x1234..." }, "message": "Sign in to Prob...", "signature": "0xabc123...", "nonce": "abc123xyz", "issuedAt": "2025-01-15T10:30:00Z", "domain": "prob.vbgf.cc" }' Logout[](https://developer.probable.markets/api/orderbook-api/authentication#logout) --------------------------------------------------------------------------------------- Log out the current user. **Endpoint:** `POST /public/api/v1/auth/logout` ### Example Request[](https://developer.probable.markets/api/orderbook-api/authentication#example-request-2) curl -X POST "https://api.probable.markets/public/api/v1/auth/logout" ### Example Response[](https://developer.probable.markets/api/orderbook-api/authentication#example-response-1) { "success": true } Verify L1 Headers[](https://developer.probable.markets/api/orderbook-api/authentication#verify-l1-headers) ------------------------------------------------------------------------------------------------------------- Verify L1 authentication headers (EIP-712 signature). **Endpoint:** `POST /public/api/v1/auth/verify/l1` ### Request Body[](https://developer.probable.markets/api/orderbook-api/authentication#request-body-1) { "chainId": 56 } ### Headers[](https://developer.probable.markets/api/orderbook-api/authentication#headers) * `prob_address` - User address * `prob_signature` - EIP-712 signature * `prob_timestamp` - Unix timestamp * `prob_nonce` - Nonce ### Example Response[](https://developer.probable.markets/api/orderbook-api/authentication#example-response-2) { "valid": true, "address": "0x1234...", "chainId": 56, "message": "Verification successful" } Verify L2 Headers[](https://developer.probable.markets/api/orderbook-api/authentication#verify-l2-headers) ------------------------------------------------------------------------------------------------------------- Verify L2 authentication headers (HMAC signature with API key). **Endpoint:** `POST /public/api/v1/auth/verify/l2` ### Request Body[](https://developer.probable.markets/api/orderbook-api/authentication#request-body-2) { "chainId": 56, "method": "POST", "path": "/public/api/v1/order/56", "body": {} } ### Headers[](https://developer.probable.markets/api/orderbook-api/authentication#headers-1) * `prob_address` - User address * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Example Response[](https://developer.probable.markets/api/orderbook-api/authentication#example-response-3) { "valid": true, "address": "0x1234...", "chainId": 56, "message": "Verification successful" } --- # Getting Started | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/getting-started#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Getting Started On this page Chevron Right This guide walks you through the complete setup process: creating a proxy wallet, authenticating with L1/L2, and submitting orders. Overview[](https://developer.probable.markets/api/orderbook-api/getting-started#overview) -------------------------------------------------------------------------------------------- All orderbook write operations (placing orders, canceling orders, etc.) require: 1. **Proxy Wallet** - A smart contract wallet created from your EOA 2. **L2 Authentication** - API credentials for authenticated requests **Complete Flow:** 1. **Create Proxy Wallet** - Set up a proxy wallet from your EOA (required for all users) 2. **Approve Tokens** - Approve token spending allowances (required before trading) 3. **L1 Authentication** - Get a nonce and authenticate with wallet signature 4. **Generate API Key** - Use L1 credentials to generate L2 API key and secret 5. **L2 Authentication** - Use API key and secret to sign requests with HMAC 6. **Submit Orders** - Use L2 credentials to place and manage orders > **Important:** > > * Before starting authentication, make sure you have created a proxy wallet. See the [Proxy Wallet Guide](https://developer.probable.markets/api/orderbook-api/proxy-wallet) > for detailed instructions. > * Before placing orders, you must approve token spending. See the [Token Approvals Guide](https://developer.probable.markets/api/orderbook-api/token-approvals) > for detailed instructions. * * * Step 0: Create Proxy Wallet (Required)[](https://developer.probable.markets/api/orderbook-api/getting-started#step-0-create-proxy-wallet-required) ----------------------------------------------------------------------------------------------------------------------------------------------------- Before authenticating, you must create a proxy wallet from your EOA. The proxy wallet address will be used as the `maker` in order creation. **Quick Start:** import { getOrCreateProxyWallet } from './proxy-wallet'; const eoaAddress = '0x...' as `0x${string}`; const proxyWalletAddress = await getOrCreateProxyWallet(eoaAddress); console.log('Proxy wallet:', proxyWalletAddress); For detailed instructions, see the [Proxy Wallet Creation Guide](https://developer.probable.markets/api/orderbook-api/proxy-wallet) . **Important Address Usage:** * **Authentication (`prob_address`)**: Always use your **EOA address** * **Order `maker` field**: Use your **proxy wallet address** * **Order `signer` field**: Use your **EOA address** * * * Step 0.5: Approve Token Spending (Required)[](https://developer.probable.markets/api/orderbook-api/getting-started#step-05-approve-token-spending-required) -------------------------------------------------------------------------------------------------------------------------------------------------------------- After creating your proxy wallet, you must approve token spending allowances before you can place orders. **Quick Start:** import { approveAllTokens } from './token-approvals'; await approveAllTokens(eoaAddress, proxyWalletAddress, account); For detailed instructions, see the [Token Approvals Guide](https://developer.probable.markets/api/orderbook-api/token-approvals) . **Required Approvals:** * USDT → CTF Token contract (for splitting/merging) * USDT → CTF Exchange (for trading) * CTF Tokens → CTF Exchange (for trading) * * * Step 1: L1 Authentication[](https://developer.probable.markets/api/orderbook-api/getting-started#step-1-l1-authentication) ----------------------------------------------------------------------------------------------------------------------------- L1 authentication uses EIP-712 signature verification with your wallet. ### 1.1 Get a Nonce[](https://developer.probable.markets/api/orderbook-api/getting-started#11-get-a-nonce) First, request a nonce from the API: curl "https://api.probable.markets/public/api/v1/auth/nonce" **Response:** { "nonce": "abc123xyz", "issuedAt": "2025-01-15T10:30:00Z" } ### 1.2 Sign the Authentication Message[](https://developer.probable.markets/api/orderbook-api/getting-started#12-sign-the-authentication-message) Create an EIP-712 signature using your wallet. The message structure should include: * Your wallet address * The nonce from step 1.1 * Current timestamp * Domain: `prob.vbgf.cc` **Example (JavaScript with ethers.js):** import { ethers } from 'ethers'; const domain = { name: 'Prob', version: '1', chainId: 56, // BSC mainnet verifyingContract: '0x...' // Your contract address }; const types = { Message: [\ { name: 'account', type: 'address' },\ { name: 'namespace', type: 'string' },\ { name: 'chainId', type: 'string' },\ { name: 'address', type: 'address' }\ ] }; const message = { account: eoaAddress, // Use EOA address for authentication namespace: 'default', chainId: '56', address: eoaAddress // Use EOA address }; const signature = await signer._signTypedData(domain, types, message); ### 1.3 Login with Signature[](https://developer.probable.markets/api/orderbook-api/getting-started#13-login-with-signature) Submit the login request with your signature: curl -X POST "https://api.probable.markets/public/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d '{ "identity": { "account": "0x1234...", "namespace": "default", "chainId": "56", "address": "0x1234..." }, "message": "Sign in to Prob...", "signature": "0xabc123...", "nonce": "abc123xyz", "issuedAt": "2025-01-15T10:30:00Z", "domain": "prob.vbgf.cc" }' * * * Step 2: Generate L2 API Key[](https://developer.probable.markets/api/orderbook-api/getting-started#step-2-generate-l2-api-key) --------------------------------------------------------------------------------------------------------------------------------- Once you're authenticated with L1, you can generate an API key for L2 authentication. ### 2.1 Prepare L1 Headers[](https://developer.probable.markets/api/orderbook-api/getting-started#21-prepare-l1-headers) For L1-authenticated requests, you need these headers: * `prob_address` - Your **EOA address** (signed by EOA) * `prob_signature` - EIP-712 signature signed by EOA * `prob_timestamp` - Current Unix timestamp * `prob_nonce` - Nonce from step 1.1 ### 2.2 Generate API Key[](https://developer.probable.markets/api/orderbook-api/getting-started#22-generate-api-key) curl -X POST "https://api.probable.markets/public/api/v1/auth/api-key/56" \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_nonce: abc123xyz" > **Note:** Use your **EOA address** in `prob_address` for authentication. The signature must be signed by the EOA. **Response:** { "apiKey": "pk_live_abc123xyz", "secret": "sk_live_def456uvw", "passphrase": "my-passphrase" } ⚠️ **Important:** Store the `secret` and `passphrase` securely. They cannot be retrieved later. You'll need these for all L2-authenticated requests. * * * Step 3: L2 Authentication (HMAC Signing)[](https://developer.probable.markets/api/orderbook-api/getting-started#step-3-l2-authentication-hmac-signing) --------------------------------------------------------------------------------------------------------------------------------------------------------- L2 authentication uses HMAC-SHA256 to sign requests with your API key and secret. ### 3.1 Create HMAC Signature[](https://developer.probable.markets/api/orderbook-api/getting-started#31-create-hmac-signature) The signature is created by hashing a combination of: * Timestamp * HTTP method (GET, POST, etc.) * Request path * Request body (if any) **Example (JavaScript):** import crypto from 'crypto'; function createL2Signature(timestamp, method, path, body, secret, passphrase) { const message = `${timestamp}${method}${path}${body ? JSON.stringify(body) : ''}`; const hmac = crypto.createHmac('sha256', secret); hmac.update(message); return hmac.digest('hex'); } const timestamp = Math.floor(Date.now() / 1000).toString(); const method = 'POST'; const path = '/public/api/v1/order/56'; const body = { /* your order data */ }; const signature = createL2Signature( timestamp, method, path, body, apiSecret, passphrase ); ### 3.2 Prepare L2 Headers[](https://developer.probable.markets/api/orderbook-api/getting-started#32-prepare-l2-headers) For L2-authenticated requests, include these headers: * `prob_address` - Your **EOA address** (same as L1) * `prob_signature` - HMAC signature (from step 3.1) * `prob_timestamp` - Current Unix timestamp * `prob_api_key` - Your API key * `prob_passphrase` - Your passphrase * * * Step 4: Submit an Order[](https://developer.probable.markets/api/orderbook-api/getting-started#step-4-submit-an-order) ------------------------------------------------------------------------------------------------------------------------- Now you can use L2 credentials to place orders. ### 4.1 Prepare Order Data[](https://developer.probable.markets/api/orderbook-api/getting-started#41-prepare-order-data) { "deferExec": false, "order": { "salt": "1234567890", "maker": "0xPROXY_WALLET...", "signer": "0xEOA_ADDRESS...", "taker": "0x0000...", "tokenId": "0xabc123...", "makerAmount": "1000000000000000000", "takerAmount": "500000000000000000", "side": "BUY", "expiration": "1735689600", "nonce": "0", "feeRateBps": "175", "signatureType": 0, "signature": "0xdef456..." }, "owner": "0xPROXY_WALLET...", "orderType": "GTC" } ### 4.2 Create HMAC Signature[](https://developer.probable.markets/api/orderbook-api/getting-started#42-create-hmac-signature) const timestamp = Math.floor(Date.now() / 1000).toString(); const method = 'POST'; const path = '/public/api/v1/order/56'; const body = JSON.stringify(orderData); const signature = createL2Signature( timestamp, method, path, body, apiSecret, passphrase ); ### 4.3 Submit Order[](https://developer.probable.markets/api/orderbook-api/getting-started#43-submit-order) curl -X POST "https://api.probable.markets/public/api/v1/order/56" \ -H "Content-Type: application/json" \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xhmac_signature..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" \ -d '{ "deferExec": false, "order": { "maker": "0xPROXY_WALLET...", "signer": "0xEOA_ADDRESS...", ... }, "owner": "0xPROXY_WALLET...", "orderType": "GTC" }' > **Note:** > > * `prob_address` header: Use your **EOA address** > * Order `maker` field: Use your **proxy wallet address** > * Order `signer` field: Use your **EOA address** > * Order `owner` field: Use your **proxy wallet address** **Response:** { "orderId": 12345, "symbol": "BTC-USD", "side": "BUY", "status": "NEW", ... } * * * Complete Example[](https://developer.probable.markets/api/orderbook-api/getting-started#complete-example) ------------------------------------------------------------------------------------------------------------ Here's a complete example in JavaScript: import crypto from 'crypto'; import axios from 'axios'; const BASE_URL = 'https://api.probable.markets'; const eoaAddress = '0x...'; // Your EOA address const proxyWalletAddress = await getOrCreateProxyWallet(eoaAddress); // Get or create proxy wallet const chainId = 56; // Step 1: Get nonce const { data: nonceData } = await axios.get(`${BASE_URL}/public/api/v1/auth/nonce`); const nonce = nonceData.nonce; // Step 2: Sign with wallet (using ethers.js) const signature = await signer._signTypedData(domain, types, message); // Step 3: Login (use EOA address for authentication) await axios.post(`${BASE_URL}/public/api/v1/auth/login`, { identity: { account: eoaAddress, namespace: 'default', chainId: '56', address: eoaAddress }, message: 'Sign in to Prob...', signature, nonce, issuedAt: new Date().toISOString(), domain: 'prob.vbgf.cc' }); // Step 4: Generate API key (with L1 headers) const timestamp = Math.floor(Date.now() / 1000).toString(); const { data: apiKeyData } = await axios.post( `${BASE_URL}/public/api/v1/auth/api-key/${chainId}`, {}, { headers: { prob_address: eoaAddress, // Use EOA address for authentication prob_signature: signature, prob_timestamp: timestamp, prob_nonce: nonce } } ); const { apiKey, secret, passphrase } = apiKeyData; // Step 5: Create L2 signature function function createL2Signature(timestamp, method, path, body, secret, passphrase) { const message = `${timestamp}${method}${path}${body ? JSON.stringify(body) : ''}`; return crypto.createHmac('sha256', secret).update(message).digest('hex'); } // Step 6: Place order (with L2 headers) const orderData = { deferExec: false, order: { /* order details */ maker: proxyWalletAddress, // Use proxy wallet address signer: eoaAddress, // Use EOA address (signs the order) // ... other order fields }, owner: proxyWalletAddress, // Use proxy wallet address orderType: 'GTC' }; const orderTimestamp = Math.floor(Date.now() / 1000).toString(); const orderPath = `/public/api/v1/order/${chainId}`; const orderSignature = createL2Signature( orderTimestamp, 'POST', orderPath, orderData, secret, passphrase ); const { data: orderResponse } = await axios.post( `${BASE_URL}${orderPath}`, orderData, { headers: { 'Content-Type': 'application/json', prob_address: eoaAddress, // Use EOA address for authentication prob_signature: orderSignature, prob_timestamp: orderTimestamp, prob_api_key: apiKey, prob_passphrase: passphrase } } ); console.log('Order placed:', orderResponse); * * * Next Steps[](https://developer.probable.markets/api/orderbook-api/getting-started#next-steps) ------------------------------------------------------------------------------------------------ * [Proxy Wallet Guide](https://developer.probable.markets/api/orderbook-api/proxy-wallet) - Detailed proxy wallet creation guide * [Authentication Reference](https://developer.probable.markets/api/orderbook-api/authentication) - Detailed authentication API specs * [API Keys Reference](https://developer.probable.markets/api/orderbook-api/api-keys) - API key management endpoints * [Orders Reference](https://developer.probable.markets/api/orderbook-api/orders) - Complete order management API --- # Complete Guide: Orderbook Integration with EOA Wallet | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-eoa-guide#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Orderbook EOA Guide On this page Chevron Right This comprehensive guide walks you through the complete process of interacting with Probable Markets orderbook using your EOA (Externally Owned Account) wallet directly, without creating a proxy wallet. This is a simpler flow that uses your wallet directly for all operations. Overview[](https://developer.probable.markets/api/orderbook-eoa-guide#overview) ---------------------------------------------------------------------------------- This guide provides a complete walkthrough for integrating with Probable Markets orderbook using your EOA wallet directly. You'll learn how to: 1. **Approve Tokens** - Grant spending allowances for USDT and CTF tokens directly from your EOA 2. **Check Balance** - Verify your EOA has sufficient USDT 3. **Create API Key** - Generate API credentials for authenticated requests 4. **Create and Sign Order** - Build an EIP-712 signed order with EOA signature 5. **Submit Order** - Send the order to the API with L2 authentication > **Note:** This guide references the implementation in `clob-examples`. For complete working code, see the [clob-examples repository](https://github.com/0xprobable/clob-examples) > . Run `bun run index-eoa.ts` to execute the EOA flow. * * * Prerequisites[](https://developer.probable.markets/api/orderbook-eoa-guide#prerequisites) -------------------------------------------------------------------------------------------- * An EOA wallet with: * BNB for transaction fees * USDT for trading (in your EOA wallet) * Access to a BSC RPC endpoint * Node.js/Bun environment with `viem` installed > **Key Difference:** Unlike the proxy wallet flow, this guide uses your EOA directly - no proxy wallet creation needed! Contract Addresses[](https://developer.probable.markets/api/orderbook-eoa-guide#contract-addresses) ------------------------------------------------------------------------------------------------------ const USDT_ADDRESS = '0x55d398326f99059fF775485246999027B3197955'; const CTF_TOKEN_ADDRESS = '0x364d05055614B506e2b9A287E4ac34167204cA83'; const CTF_EXCHANGE_ADDRESS = '0xF99F5367ce708c66F0860B77B4331301A5597c86'; const CHAIN_ID = 56; // BSC Mainnet * * * Step 1: Approve Tokens[](https://developer.probable.markets/api/orderbook-eoa-guide#step-1-approve-tokens) ------------------------------------------------------------------------------------------------------------- Unlike the proxy wallet flow, token approvals are done directly from your EOA using standard ERC20/ERC1155 transactions. You need three approvals: 1. **USDT → CTF Token Contract** (for splitting/merging positions) 2. **USDT → CTF Exchange** (for trading) 3. **CTF Tokens → CTF Exchange** (for trading) ### 1.1 Check Existing Approvals[](https://developer.probable.markets/api/orderbook-eoa-guide#11-check-existing-approvals) import { maxUint256 } from 'viem'; import { getContract } from 'viem'; import { ERC20_ABI, ERC1155_ABI } from './config'; async function checkAllApprovals(eoaAddress: `0x${string}`) { const results = await publicClient.multicall({ contracts: [\ {\ address: USDT_ADDRESS,\ abi: ERC20_ABI,\ functionName: 'allowance',\ args: [eoaAddress, CTF_TOKEN_ADDRESS],\ },\ {\ address: USDT_ADDRESS,\ abi: ERC20_ABI,\ functionName: 'allowance',\ args: [eoaAddress, CTF_EXCHANGE_ADDRESS],\ },\ {\ address: CTF_TOKEN_ADDRESS,\ abi: ERC1155_ABI,\ functionName: 'isApprovedForAll',\ args: [eoaAddress, CTF_EXCHANGE_ADDRESS],\ },\ ], }); return { needsUSDTForCTFToken: results[0].status === 'success' && results[0].result < maxUint256, needsUSDTForExchange: results[1].status === 'success' && results[1].result < maxUint256, needsCTFTokenForExchange: results[2].status === 'success' && !results[2].result, }; } ### 1.2 Execute Approvals Directly[](https://developer.probable.markets/api/orderbook-eoa-guide#12-execute-approvals-directly) All approvals are executed as direct transactions from your EOA: async function approveTokensEOA(eoaAddress: `0x${string}`) { const { needsUSDTForCTFToken, needsUSDTForExchange, needsCTFTokenForExchange } = await checkAllApprovals(eoaAddress); // Approve USDT for CTF Token if (needsUSDTForCTFToken) { const usdtContract = getContract({ address: USDT_ADDRESS, abi: ERC20_ABI, client: { public: publicClient, wallet: walletClient }, }); const hash = await usdtContract.write.approve([CTF_TOKEN_ADDRESS, maxUint256]); await publicClient.waitForTransactionReceipt({ hash }); } // Approve USDT for Exchange if (needsUSDTForExchange) { const usdtContract = getContract({ address: USDT_ADDRESS, abi: ERC20_ABI, client: { public: publicClient, wallet: walletClient }, }); const hash = await usdtContract.write.approve([CTF_EXCHANGE_ADDRESS, maxUint256]); await publicClient.waitForTransactionReceipt({ hash }); } // Approve CTF Tokens for Exchange if (needsCTFTokenForExchange) { const ctfTokenContract = getContract({ address: CTF_TOKEN_ADDRESS, abi: ERC1155_ABI, client: { public: publicClient, wallet: walletClient }, }); const hash = await ctfTokenContract.write.setApprovalForAll([CTF_EXCHANGE_ADDRESS, true]); await publicClient.waitForTransactionReceipt({ hash }); } } * * * Step 2: Check USDT Balance[](https://developer.probable.markets/api/orderbook-eoa-guide#step-2-check-usdt-balance) --------------------------------------------------------------------------------------------------------------------- Verify that your EOA has sufficient USDT for trading: async function checkUSDTBalanceEOA(eoaAddress: `0x${string}`) { const usdtContract = getContract({ address: USDT_ADDRESS, abi: ERC20_ABI, client: { public: publicClient }, }); const decimals = await usdtContract.read.decimals(); const decimalsMultiplier = 10n ** BigInt(decimals); const balance = await usdtContract.read.balanceOf([eoaAddress]); const balanceInUSDT = Number(balance) / Number(decimalsMultiplier); if (balanceInUSDT <= 1) { throw new Error('Insufficient USDT balance. Please deposit at least 1 USDT to your EOA.'); } console.log(`USDT Balance: ${balanceInUSDT.toFixed(6)} USDT`); return balanceInUSDT; } * * * Step 3: Create API Key[](https://developer.probable.markets/api/orderbook-eoa-guide#step-3-create-api-key) ------------------------------------------------------------------------------------------------------------- API keys are created using L1 authentication (EIP-712 signature) with your EOA. The process is the same as the proxy wallet flow, but you use your EOA address directly. ### 3.1 Build L1 Authentication Signature[](https://developer.probable.markets/api/orderbook-eoa-guide#31-build-l1-authentication-signature) async function buildL1Signature( walletClient: WalletClient, chainId: number, timestamp: number, nonce: number ): Promise { const eoaAddress = walletClient.account.address; const MSG_TO_SIGN = "This message attests that I control the given wallet"; const domain = { name: 'ClobAuthDomain', version: '1', chainId: chainId, }; const types = { ClobAuth: [\ { name: 'address', type: 'address' },\ { name: 'timestamp', type: 'string' },\ { name: 'nonce', type: 'uint256' },\ { name: 'message', type: 'string' },\ ], }; const message = { address: eoaAddress, timestamp: timestamp.toString(), nonce: nonce, message: MSG_TO_SIGN, }; return await walletClient.signTypedData({ domain, types, primaryType: 'ClobAuth', message, }); } ### 3.2 Create API Key[](https://developer.probable.markets/api/orderbook-eoa-guide#32-create-api-key) import axios from 'axios'; async function createApiKey(walletClient: WalletClient): Promise<{ key: string; secret: string; passphrase: string; }> { const eoaAddress = walletClient.account.address; const timestamp = Math.floor(Date.now() / 1000); const nonce = 0; const signature = await buildL1Signature( walletClient, CHAIN_ID, timestamp, nonce ); const response = await axios.post( `https://api.probable.markets/public/api/v1/auth/api-key/${CHAIN_ID}`, {}, { headers: { prob_address: eoaAddress, prob_signature: signature, prob_timestamp: timestamp.toString(), prob_nonce: nonce.toString(), }, } ); return { key: response.data.apiKey, secret: response.data.secret, passphrase: response.data.passphrase, }; } * * * Step 4: Create and Sign Order[](https://developer.probable.markets/api/orderbook-eoa-guide#step-4-create-and-sign-order) --------------------------------------------------------------------------------------------------------------------------- Orders are created using EIP-712 typed data signing. For EOA wallets, the key difference is: * **Signature Type**: `SignatureType.EOA` (instead of `PROB_GNOSIS_SAFE`) * **Maker**: Your EOA address (same as signer) * **Signer**: Your EOA address ### 4.1 Build Order Data[](https://developer.probable.markets/api/orderbook-eoa-guide#41-build-order-data) import { parseUnits } from 'viem'; interface UserOrder { tokenID: string; price: number; size: number; side: 0 | 1; // 0 = BUY, 1 = SELL feeRateBps?: number; // Max taker fee in basis points (175-1000) nonce?: number; } function buildOrderData( userOrder: UserOrder, eoaAddress: string, tickSize: '0.01' | '0.1' | '0.001' | '0.0001' ): { maker: string; signer: string; tokenId: string; makerAmount: string; takerAmount: string; side: number; feeRateBps: string; nonce: string; expiration: string; signatureType: number; } { // Calculate raw amounts (same as proxy wallet flow) const { rawMakerAmt, rawTakerAmt } = calculateOrderAmounts( userOrder.side, userOrder.size, userOrder.price, tickSize ); const makerAmount = parseUnits(rawMakerAmt.toString(), 18).toString(); const takerAmount = parseUnits(rawTakerAmt.toString(), 18).toString(); const feeRateBps = userOrder.feeRateBps ?? 175; if (feeRateBps < 175 || feeRateBps > 1000) { throw new Error('feeRateBps must be between 175 and 1000 (inclusive)'); } return { maker: eoaAddress, // EOA is both maker and signer signer: eoaAddress, // EOA signs the order tokenId: userOrder.tokenID, makerAmount, takerAmount, side: userOrder.side, feeRateBps: feeRateBps.toString(), nonce: (userOrder.nonce || 0).toString(), expiration: '0', signatureType: 0, // SignatureType.EOA }; } ### 4.2 Sign Order with EIP-712[](https://developer.probable.markets/api/orderbook-eoa-guide#42-sign-order-with-eip-712) async function signOrder( orderData: ReturnType, walletClient: WalletClient, salt: string ): Promise { const domain = { name: 'Probable CTF Exchange', version: '1', chainId: CHAIN_ID, verifyingContract: CTF_EXCHANGE_ADDRESS, }; const types = { Order: [\ { name: 'salt', type: 'uint256' },\ { name: 'maker', type: 'address' },\ { name: 'signer', type: 'address' },\ { name: 'taker', type: 'address' },\ { name: 'tokenId', type: 'uint256' },\ { name: 'makerAmount', type: 'uint256' },\ { name: 'takerAmount', type: 'uint256' },\ { name: 'expiration', type: 'uint256' },\ { name: 'nonce', type: 'uint256' },\ { name: 'feeRateBps', type: 'uint256' },\ { name: 'side', type: 'uint8' },\ { name: 'signatureType', type: 'uint8' },\ ], }; const taker = '0x0000000000000000000000000000000000000000'; const message = { salt: BigInt(salt), maker: orderData.maker as `0x${string}`, signer: orderData.signer as `0x${string}`, taker: taker as `0x${string}`, tokenId: BigInt(orderData.tokenId), makerAmount: BigInt(orderData.makerAmount), takerAmount: BigInt(orderData.takerAmount), expiration: BigInt(orderData.expiration), nonce: BigInt(orderData.nonce), feeRateBps: BigInt(orderData.feeRateBps), side: orderData.side, signatureType: orderData.signatureType, }; return await walletClient.signTypedData({ domain, types, primaryType: 'Order', message, }); } * * * Step 5: Submit Order to API[](https://developer.probable.markets/api/orderbook-eoa-guide#step-5-submit-order-to-api) ----------------------------------------------------------------------------------------------------------------------- Submit the signed order to the API using L2 authentication. The key difference is passing `accountType: 'eoa'` in the API request. ### 5.1 Build L2 HMAC Signature[](https://developer.probable.markets/api/orderbook-eoa-guide#51-build-l2-hmac-signature) import * as crypto from 'crypto'; function buildL2Signature( secret: string, timestamp: number, method: string, path: string, body: string ): string { const message = `${timestamp}${method}${path}${body}`; const base64Secret = Buffer.from(secret, 'base64'); const hmac = crypto.createHmac('sha256', base64Secret); const sig = hmac.update(message).digest('base64'); // URL-safe base64 encoding return sig.replace(/\+/g, '-').replace(/\//g, '_'); } ### 5.2 Submit Order[](https://developer.probable.markets/api/orderbook-eoa-guide#52-submit-order) async function submitOrder( signedOrder: { salt: string; maker: string; signer: string; taker: string; tokenId: string; makerAmount: string; takerAmount: string; side: number; expiration: string; nonce: string; feeRateBps: string; signatureType: number; signature: string; }, apiKey: string, secret: string, passphrase: string, eoaAddress: string ) { const requestBody = { deferExec: true, order: { salt: signedOrder.salt, maker: signedOrder.maker, signer: signedOrder.signer, taker: signedOrder.taker, tokenId: signedOrder.tokenId, makerAmount: signedOrder.makerAmount, takerAmount: signedOrder.takerAmount, side: signedOrder.side === 0 ? 'BUY' : 'SELL', expiration: signedOrder.expiration, nonce: signedOrder.nonce, feeRateBps: signedOrder.feeRateBps, signatureType: signedOrder.signatureType, signature: signedOrder.signature, }, owner: signedOrder.maker, // EOA address orderType: 'GTC', }; const timestamp = Math.floor(Date.now() / 1000); const method = 'POST'; const path = `/public/api/v1/order/${CHAIN_ID}`; const bodyString = JSON.stringify(requestBody); const signature = buildL2Signature(secret, timestamp, method, path, bodyString); const response = await axios.post( `https://api.probable.markets${path}`, requestBody, { headers: { 'Content-Type': 'application/json', prob_address: eoaAddress, prob_signature: signature, prob_timestamp: timestamp.toString(), prob_api_key: apiKey, prob_passphrase: passphrase, prob_account_type: 'eoa', // Important: specify EOA account type }, } ); return response.data; } * * * Complete Example[](https://developer.probable.markets/api/orderbook-eoa-guide#complete-example) -------------------------------------------------------------------------------------------------- Here's a complete example that ties everything together: async function placeOrderFromEOA( walletClient: WalletClient, tokenId: string, price: number, size: number, side: 0 | 1 ) { const eoaAddress = walletClient.account.address; // Step 1: Approve tokens const approvals = await checkAllApprovals(eoaAddress); if (approvals.needsUSDTForCTFToken || approvals.needsUSDTForExchange || approvals.needsCTFTokenForExchange) { await approveTokensEOA(eoaAddress); } // Step 2: Check USDT balance await checkUSDTBalanceEOA(eoaAddress); // Step 3: Create API key const apiKey = await createApiKey(walletClient); // Step 4: Create and sign order const userOrder: UserOrder = { tokenID: tokenId, price, size, side, feeRateBps: 175, nonce: 0, }; const orderData = buildOrderData(userOrder, eoaAddress, '0.01'); const salt = `${Math.round(Math.random() * Date.now())}`; const signature = await signOrder(orderData, walletClient, salt); const signedOrder = { ...orderData, salt, taker: '0x0000000000000000000000000000000000000000', signature, }; // Step 5: Submit order const result = await submitOrder( signedOrder, apiKey.key, apiKey.secret, apiKey.passphrase, eoaAddress ); console.log('Order placed:', result); return result; } * * * Key Differences from Proxy Wallet Flow[](https://developer.probable.markets/api/orderbook-eoa-guide#key-differences-from-proxy-wallet-flow) ---------------------------------------------------------------------------------------------------------------------------------------------- | Aspect | Proxy Wallet Flow | EOA Flow | | --- | --- | --- | | **Wallet Setup** | Create Gnosis Safe proxy wallet | Use EOA directly | | **Token Approvals** | Via Safe transactions (batched) | Direct ERC20/ERC1155 transactions | | **Order Maker** | Proxy wallet address | EOA address | | **Order Signer** | EOA address | EOA address | | **Signature Type** | `PROB_GNOSIS_SAFE` (1) | `EOA` (0) | | **API Account Type** | Not specified (defaults to proxy) | `'eoa'` | | **USDT Location** | Proxy wallet | EOA wallet | | **Complexity** | Higher (Safe SDK required) | Lower (standard transactions) | * * * Advantages of EOA Flow[](https://developer.probable.markets/api/orderbook-eoa-guide#advantages-of-eoa-flow) -------------------------------------------------------------------------------------------------------------- 1. **Simpler Setup** - No proxy wallet creation needed 2. **Lower Gas Costs** - Direct transactions are cheaper than Safe transactions 3. **Faster Execution** - No need to wait for proxy wallet deployment 4. **Direct Control** - Full control over your funds in your EOA When to Use EOA Flow[](https://developer.probable.markets/api/orderbook-eoa-guide#when-to-use-eoa-flow) ---------------------------------------------------------------------------------------------------------- * You want a simpler integration without proxy wallet complexity * You're comfortable managing funds directly in your EOA * You want lower gas costs * You don't need the additional security features of a Safe wallet * * * Next Steps[](https://developer.probable.markets/api/orderbook-eoa-guide#next-steps) -------------------------------------------------------------------------------------- * [Orderbook Complete Guide (Proxy Wallet)](https://developer.probable.markets/api/orderbook-complete-guide) - Guide for proxy wallet flow with additional security features * [Orderbook API Overview](https://developer.probable.markets/api/orderbook-api/overview) - Complete API reference * [TypeScript SDK](https://developer.probable.markets/api/orderbook-api/typescript-sdk) - SDK documentation * [Authentication Guide](https://developer.probable.markets/api/orderbook-api/authentication) - Authentication details * * * Choosing Between EOA and Proxy Wallet Flow[](https://developer.probable.markets/api/orderbook-eoa-guide#choosing-between-eoa-and-proxy-wallet-flow) ------------------------------------------------------------------------------------------------------------------------------------------------------ **Use EOA Flow if:** * You want a simpler setup without proxy wallet complexity * You prefer lower gas costs * You're comfortable managing funds directly in your EOA * You don't need Safe wallet features **Use Proxy Wallet Flow if:** * You want additional security features (multi-sig, recovery, etc.) * You prefer to separate trading funds from your main EOA * You need advanced Safe wallet capabilities * You want to batch multiple transactions together --- # Token Approvals | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/token-approvals#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Token Approvals On this page Chevron Right After creating a proxy wallet, you need to approve token spending allowances to enable trading operations. This guide shows you how to approve the necessary tokens using TypeScript and Viem. Overview[](https://developer.probable.markets/api/orderbook-api/token-approvals#overview) -------------------------------------------------------------------------------------------- To enable trading on the orderbook, you need to approve: 1. **USDT (ERC20)** - Approve spending to: * CTF Token contract (for splitting/merging operations) * CTF Exchange contract (for trading operations) 2. **CTF Tokens (ERC1155)** - Approve spending to: * CTF Exchange contract (for trading operations) Contract Addresses[](https://developer.probable.markets/api/orderbook-api/token-approvals#contract-addresses) ---------------------------------------------------------------------------------------------------------------- **BSC Mainnet:** * USDT (ERC20): `0x364d05055614B506e2b9A287E4ac34167204cA83` * CTF Token Contract (ERC1155): `0xc53a8b3bF7934fe94305Ed7f84a2ea8ce1028a12` * CTF Exchange: `0xF99F5367ce708c66F0860B77B4331301A5597c86` Prerequisites[](https://developer.probable.markets/api/orderbook-api/token-approvals#prerequisites) ------------------------------------------------------------------------------------------------------ Install required dependencies: npm install viem @safe-global/protocol-kit **Note:** We'll use Safe Protocol Kit for creating Safe transactions, but all interactions will use viem. The Safe SDK can work with viem's transport adapter. Step 1: Setup Viem Clients[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-1-setup-viem-clients) ------------------------------------------------------------------------------------------------------------------------------- import { createWalletClient, createPublicClient, http, custom } from 'viem'; import { bsc } from 'viem/chains'; import { privateKeyToAccount } from 'viem/accounts'; import Safe, { MetaTransactionData, OperationType } from '@safe-global/protocol-kit'; // Setup account and clients const account = privateKeyToAccount('0x...' as `0x${string}`); const eoaAddress = account.address; const publicClient = createPublicClient({ chain: bsc, transport: http(), }); const walletClient = createWalletClient({ account, chain: bsc, transport: http(), }); // Get proxy wallet address (from previous step) const proxyWalletAddress = await computeProxyAddress(eoaAddress); Step 2: Initialize Safe Protocol Kit[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-2-initialize-safe-protocol-kit) --------------------------------------------------------------------------------------------------------------------------------------------------- Since the proxy wallet is a Gnosis Safe, you need to use the Safe Protocol Kit to create and sign transactions. The Safe SDK can work with viem's transport: // Initialize Safe Protocol Kit with viem transport const safeProtocolKit = await Safe.init({ provider: walletClient.transport, // Use viem's transport signer: eoaAddress, safeAddress: proxyWalletAddress, }); **Note:** Safe transactions will be created and executed directly using the Safe SDK's `executeTransaction` method. Step 3: Define Contract ABIs[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-3-define-contract-abis) ----------------------------------------------------------------------------------------------------------------------------------- import { parseAbi, encodeFunctionData, maxUint256 } from 'viem'; // ERC20 ABI for approve function const erc20Abi = parseAbi([\ 'function approve(address spender, uint256 amount) external returns (bool)',\ 'function allowance(address owner, address spender) external view returns (uint256)',\ ]); // ERC1155 ABI for setApprovalForAll function const erc1155Abi = parseAbi([\ 'function setApprovalForAll(address operator, bool approved) external',\ 'function isApprovedForAll(address account, address operator) external view returns (bool)',\ ]); Step 4: Check Current Approvals[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-4-check-current-approvals) ----------------------------------------------------------------------------------------------------------------------------------------- Before approving, check if approvals are already set: const USDT_ADDRESS = '0x364d05055614B506e2b9A287E4ac34167204cA83' as const; const CTF_TOKEN_ADDRESS = '0xc53a8b3bF7934fe94305Ed7f84a2ea8ce1028a12' as const; const CTF_EXCHANGE_ADDRESS = '0xF99F5367ce708c66F0860B77B4331301A5597c86' as const; async function checkApprovals(proxyWalletAddress: `0x${string}`) { // Check USDT approval to CTF Token contract const usdtToCtfAllowance = await publicClient.readContract({ address: USDT_ADDRESS, abi: erc20Abi, functionName: 'allowance', args: [proxyWalletAddress, CTF_TOKEN_ADDRESS], }); // Check USDT approval to CTF Exchange const usdtToExchangeAllowance = await publicClient.readContract({ address: USDT_ADDRESS, abi: erc20Abi, functionName: 'allowance', args: [proxyWalletAddress, CTF_EXCHANGE_ADDRESS], }); // Check CTF Token approval to CTF Exchange const ctfToExchangeApproved = await publicClient.readContract({ address: CTF_TOKEN_ADDRESS, abi: erc1155Abi, functionName: 'isApprovedForAll', args: [proxyWalletAddress, CTF_EXCHANGE_ADDRESS], }); return { usdtToCtf: usdtToCtfAllowance > 0n, usdtToExchange: usdtToExchangeAllowance > 0n, ctfToExchange: ctfToExchangeApproved, }; } const approvals = await checkApprovals(proxyWalletAddress); console.log('Current approvals:', approvals); Step 5: Create Approval Transactions[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-5-create-approval-transactions) --------------------------------------------------------------------------------------------------------------------------------------------------- Create Safe transactions for the approvals: async function createApprovalTransactions( proxyWalletAddress: `0x${string}` ): Promise { const transactions: MetaTransactionData[] = []; // Approve USDT to CTF Token contract transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [CTF_TOKEN_ADDRESS, maxUint256], }), value: '0', operation: OperationType.Call, }); // Approve USDT to CTF Exchange transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [CTF_EXCHANGE_ADDRESS, maxUint256], }), value: '0', operation: OperationType.Call, }); // Approve CTF Tokens to CTF Exchange (setApprovalForAll) transactions.push({ to: CTF_TOKEN_ADDRESS, data: encodeFunctionData({ abi: erc1155Abi, functionName: 'setApprovalForAll', args: [CTF_EXCHANGE_ADDRESS, true], }), value: '0', operation: OperationType.Call, }); return transactions; } Step 6: Execute Approvals[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-6-execute-approvals) ----------------------------------------------------------------------------------------------------------------------------- Create and execute the Safe transaction directly: async function approveTokens( proxyWalletAddress: `0x${string}` ) { // Create transactions const transactions = await createApprovalTransactions(proxyWalletAddress); // Create Safe transaction const safeTransaction = await safeProtocolKit.createTransaction({ transactions, }); // Execute the transaction directly using the Safe SDK // The SDK will handle signing and execution const executeTxResponse = await safeProtocolKit.executeTransaction(safeTransaction); console.log('Transaction hash:', executeTxResponse.hash); // Wait for transaction confirmation using viem const receipt = await publicClient.waitForTransactionReceipt({ hash: executeTxResponse.hash as `0x${string}`, }); console.log('Transaction confirmed:', receipt.transactionHash); return receipt; } Step 7: Verify Approvals[](https://developer.probable.markets/api/orderbook-api/token-approvals#step-7-verify-approvals) --------------------------------------------------------------------------------------------------------------------------- After execution, verify that approvals were set correctly: async function verifyApprovals(proxyWalletAddress: `0x${string}`) { const approvals = await checkApprovals(proxyWalletAddress); if (!approvals.usdtToCtf) { throw new Error('USDT approval to CTF Token contract failed'); } if (!approvals.usdtToExchange) { throw new Error('USDT approval to CTF Exchange failed'); } if (!approvals.ctfToExchange) { throw new Error('CTF Token approval to CTF Exchange failed'); } console.log('All approvals verified successfully'); } await verifyApprovals(proxyWalletAddress); Complete Example[](https://developer.probable.markets/api/orderbook-api/token-approvals#complete-example) ------------------------------------------------------------------------------------------------------------ Here's a complete example that checks, creates, and executes approvals: import { createWalletClient, createPublicClient, http, encodeFunctionData, maxUint256, parseAbi } from 'viem'; import { bsc } from 'viem/chains'; import { privateKeyToAccount } from 'viem/accounts'; import Safe, { MetaTransactionData, OperationType } from '@safe-global/protocol-kit'; // Contract addresses const USDT_ADDRESS = '0x364d05055614B506e2b9A287E4ac34167204cA83' as const; const CTF_TOKEN_ADDRESS = '0xc53a8b3bF7934fe94305Ed7f84a2ea8ce1028a12' as const; const CTF_EXCHANGE_ADDRESS = '0xF99F5367ce708c66F0860B77B4331301A5597c86' as const; // ABIs const erc20Abi = parseAbi([\ 'function approve(address spender, uint256 amount) external returns (bool)',\ 'function allowance(address owner, address spender) external view returns (uint256)',\ ]); const erc1155Abi = parseAbi([\ 'function setApprovalForAll(address operator, bool approved) external',\ 'function isApprovedForAll(address account, address operator) external view returns (bool)',\ ]); async function approveAllTokens( eoaAddress: `0x${string}`, proxyWalletAddress: `0x${string}`, account: ReturnType ) { // Setup clients const publicClient = createPublicClient({ chain: bsc, transport: http(), }); const walletClient = createWalletClient({ account, chain: bsc, transport: http(), }); // Initialize Safe Protocol Kit with viem transport const safeProtocolKit = await Safe.init({ provider: walletClient.transport, signer: eoaAddress, safeAddress: proxyWalletAddress, }); // Check current approvals const [usdtToCtfAllowance, usdtToExchangeAllowance, ctfToExchangeApproved] = await Promise.all([\ publicClient.readContract({\ address: USDT_ADDRESS,\ abi: erc20Abi,\ functionName: 'allowance',\ args: [proxyWalletAddress, CTF_TOKEN_ADDRESS],\ }),\ publicClient.readContract({\ address: USDT_ADDRESS,\ abi: erc20Abi,\ functionName: 'allowance',\ args: [proxyWalletAddress, CTF_EXCHANGE_ADDRESS],\ }),\ publicClient.readContract({\ address: CTF_TOKEN_ADDRESS,\ abi: erc1155Abi,\ functionName: 'isApprovedForAll',\ args: [proxyWalletAddress, CTF_EXCHANGE_ADDRESS],\ }),\ ]); // Build transactions for missing approvals const transactions: MetaTransactionData[] = []; if (usdtToCtfAllowance === 0n) { transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [CTF_TOKEN_ADDRESS, maxUint256], }), value: '0', operation: OperationType.Call, }); } if (usdtToExchangeAllowance === 0n) { transactions.push({ to: USDT_ADDRESS, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [CTF_EXCHANGE_ADDRESS, maxUint256], }), value: '0', operation: OperationType.Call, }); } if (!ctfToExchangeApproved) { transactions.push({ to: CTF_TOKEN_ADDRESS, data: encodeFunctionData({ abi: erc1155Abi, functionName: 'setApprovalForAll', args: [CTF_EXCHANGE_ADDRESS, true], }), value: '0', operation: OperationType.Call, }); } // If all approvals are already set, return early if (transactions.length === 0) { console.log('All approvals already set'); return; } // Create Safe transaction const safeTransaction = await safeProtocolKit.createTransaction({ transactions, }); // Execute the transaction directly using the Safe SDK // The SDK will handle signing and execution const executeTxResponse = await safeProtocolKit.executeTransaction(safeTransaction); console.log('Transaction hash:', executeTxResponse.hash); // Wait for confirmation using viem const receipt = await publicClient.waitForTransactionReceipt({ hash: executeTxResponse.hash as `0x${string}`, }); console.log('Token approvals executed:', receipt.transactionHash); return receipt; } // Usage const account = privateKeyToAccount('0x...' as `0x${string}`); const eoaAddress = account.address; const proxyWalletAddress = await computeProxyAddress(eoaAddress); await approveAllTokens(eoaAddress, proxyWalletAddress, account); Important Notes[](https://developer.probable.markets/api/orderbook-api/token-approvals#important-notes) ---------------------------------------------------------------------------------------------------------- 1. **Gas Fees**: Executing approvals requires BNB for gas fees on BSC. 2. **Max Approval**: The example uses `maxUint256` for ERC20 approvals, which allows unlimited spending. This is standard practice but be aware of the implications. 3. **ERC1155 Approval**: `setApprovalForAll` approves all token IDs for the operator. This is the standard approach for ERC1155 tokens. 4. **Safe Transactions**: Since the proxy wallet is a Gnosis Safe, all transactions must be created and executed through the Safe Protocol Kit using the `executeTransaction` method. 5. **Idempotent**: It's safe to run the approval function multiple times. The example checks existing approvals before creating new transactions. Next Steps[](https://developer.probable.markets/api/orderbook-api/token-approvals#next-steps) ------------------------------------------------------------------------------------------------ After approving tokens, you can proceed to: * [Place Orders](https://developer.probable.markets/api/orderbook-api/orders) - Start trading on the orderbook * [Get Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) - Complete authentication and trading setup --- # Orders API Reference | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/orders#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Orders On this page Chevron Right Complete reference documentation for order management endpoints. > **Authentication Required:** All order write operations (place, cancel) require L2 authentication. See the [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) > to learn how to set up L2 authentication. Place Order[](https://developer.probable.markets/api/orderbook-api/orders#place-order) ----------------------------------------------------------------------------------------- Create a new order. **Endpoint:** `POST /public/api/v1/order/{chainId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/orders#path-parameters) * `chainId` (required, number) - Chain ID ### Headers (L2 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/orders#headers-l2-authentication-required) * `prob_address` - User address * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Request Body[](https://developer.probable.markets/api/orderbook-api/orders#request-body) { "deferExec": true, "order": { "salt": "1234567890", "maker": "0xPROXY_WALLET...", "signer": "0xEOA_ADDRESS...", "taker": "0x0000...", "tokenId": "0xabc123...", "makerAmount": "1000000000000000000", "takerAmount": "500000000000000000", "side": "BUY", "expiration": "1735689600", "nonce": "0", "feeRateBps": "175", "signatureType": 0, "signature": "0xdef456..." }, "owner": "0xPROXY_WALLET...", "orderType": "GTC" } > **Address Usage:** > > * `maker`: Use your **proxy wallet address** > * `signer`: Use your **EOA address** (signs the order) > * `owner`: Use your **proxy wallet address** ### Parameters[](https://developer.probable.markets/api/orderbook-api/orders#parameters) * `deferExec` (required, boolean) - Defer execution * `order` (required, object) - Order details * `salt` (required, string) - Random salt * `maker` (required, string) - **Proxy wallet address** (the wallet that will hold the position) * `signer` (required, string) - **EOA address** (the address that signs the order) * `taker` (required, string) - Taker address (0x0000... for open orders) * `tokenId` (required, string) - CTF token ID * `makerAmount` (required, string) - Maker amount in wei * `takerAmount` (required, string) - Taker amount in wei * `side` (required, string) - "BUY" or "SELL" * `expiration` (required, string) - Expiration timestamp * `nonce` (required, string) - Nonce * `feeRateBps` (required, string) - Max taker fee in basis points (must be 175-1000) * `signatureType` (required, number) - Signature type * `signature` (required, string) - Order signature * `owner` (required, string) - **Proxy wallet address** (owner of the order) * `orderType` (required, string) - Order type: "GTC" or "IOC" ### Order Types[](https://developer.probable.markets/api/orderbook-api/orders#order-types) * **GTC** (Good Till Cancel) - Order remains active until canceled * **IOC** (Immediate Or Cancel) - Execute immediately or cancel ### Example Request[](https://developer.probable.markets/api/orderbook-api/orders#example-request) curl -X POST "https://api.probable.markets/public/api/v1/order/56" \ -H "Content-Type: application/json" \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" \ -d '{ "deferExec": true, "order": { "salt": "1234567890", "maker": "0xPROXY_WALLET...", "signer": "0xEOA_ADDRESS...", "taker": "0x0000...", "tokenId": "0xabc123...", "makerAmount": "1000000000000000000", "takerAmount": "500000000000000000", "side": "BUY", "expiration": "1735689600", "nonce": "0", "feeRateBps": "175", "signatureType": 0, "signature": "0xdef456..." }, "owner": "0xPROXY_WALLET...", "orderType": "GTC" }' ### Example Response[](https://developer.probable.markets/api/orderbook-api/orders#example-response) { "orderId": 12345, "clientOrderId": "my-order-123", "symbol": "BTC-USD", "side": "BUY", "type": "LIMIT", "timeInForce": "GTC", "price": "0.5", "origQty": "1.0", "executedQty": "0.0", "cumQuote": "0.0", "status": "NEW", "time": 1705312200000, "updateTime": 1705312200000, "avgPrice": "0.0", "origType": "LIMIT", "tokenId": "0xabc123...", "ctfTokenId": "0xabc123...", "stopPrice": "0.0", "orderListId": -1, "cumQty": "0.0" } * * * Get Order[](https://developer.probable.markets/api/orderbook-api/orders#get-order) ------------------------------------------------------------------------------------- Retrieve order details by order ID. **Endpoint:** `GET /public/api/v1/orders/{chainId}/{orderId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/orders#path-parameters-1) * `chainId` (required, number) - Chain ID * `orderId` (required, string) - Order ID ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orders#query-parameters) * `tokenId` (required, string) - CTF token ID (symbol) * `origClientOrderId` (optional, string) - Client order ID * `needOrigParam` (optional, boolean) - Need original request parameter ### Headers (L2 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/orders#headers-l2-authentication-required-1) * `prob_address` - **EOA address** (signed by EOA) * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Example Request[](https://developer.probable.markets/api/orderbook-api/orders#example-request-1) curl "https://api.probable.markets/public/api/v1/orders/56/12345?tokenId=0xabc123..." \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" ### Example Response[](https://developer.probable.markets/api/orderbook-api/orders#example-response-1) Same structure as Place Order response. * * * Cancel Order[](https://developer.probable.markets/api/orderbook-api/orders#cancel-order) ------------------------------------------------------------------------------------------- Cancel an order by order ID. **Endpoint:** `DELETE /public/api/v1/order/{chainId}/{orderId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/orders#path-parameters-2) * `chainId` (required, number) - Chain ID * `orderId` (required, string) - Order ID ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orders#query-parameters-1) * `tokenId` (required, string) - CTF token ID (symbol) * `origClientOrderId` (optional, string) - Client order ID * `needOrigParam` (optional, boolean) - Need original request parameter ### Headers (L2 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/orders#headers-l2-authentication-required-2) * `prob_address` - **EOA address** (signed by EOA) * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Example Request[](https://developer.probable.markets/api/orderbook-api/orders#example-request-2) curl -X DELETE "https://api.probable.markets/public/api/v1/order/56/12345?tokenId=0xabc123..." \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" ### Example Response[](https://developer.probable.markets/api/orderbook-api/orders#example-response-2) Same structure as Place Order response, with `status: "CANCELED"`. * * * Get Open Orders[](https://developer.probable.markets/api/orderbook-api/orders#get-open-orders) ------------------------------------------------------------------------------------------------- Retrieve all open orders for a user. **Endpoint:** `GET /public/api/v1/orders/{chainId}/open` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/orders#path-parameters-3) * `chainId` (required, number) - Chain ID ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orders#query-parameters-2) * `eventId` (optional, string) - Filter by event ID * `token_ids` (optional, array) - Filter by token IDs * `page` (optional, number) - Page number * `limit` (optional, number) - Results per page ### Headers (L2 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/orders#headers-l2-authentication-required-3) * `prob_address` - **EOA address** (signed by EOA) * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Example Request[](https://developer.probable.markets/api/orderbook-api/orders#example-request-3) curl "https://api.probable.markets/public/api/v1/orders/56/open?page=1&limit=20" \ -H "prob_address: 0xEOA_ADDRESS..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" ### Example Response[](https://developer.probable.markets/api/orderbook-api/orders#example-response-3) { "orders": [\ {\ "orderId": 12345,\ "symbol": "BTC-USD",\ "side": "BUY",\ "status": "NEW",\ ...\ }\ ], "pagination": { "page": 1, "limit": 20, "total": 50 } } --- # User Data | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/data#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu User Data On this page Chevron Right Endpoints for retrieving user activity, positions, and profit/loss data. User Activity[](https://developer.probable.markets/api/orderbook-api/data#user-activity) ------------------------------------------------------------------------------------------- Get user activity feed with comprehensive filtering options. **Endpoint:** `GET /public/api/v1/activity` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/data#query-parameters) * `user` (required, string) - User address * `limit` (optional, number) - Maximum number of results * `offset` (optional, number) - Offset for pagination * `market` (optional, string or array) - Comma-separated list of condition IDs. Mutually exclusive with eventId * `eventId` (optional, number or array) - Comma-separated list of event IDs. Mutually exclusive with market * `type` (optional, array) - Activity types: "TRADE", "SPLIT", "MERGE", "REDEEM", "REWARD", "CONVERSION" * `start` (optional, number) - Start timestamp * `end` (optional, number) - End timestamp * `sortBy` (optional, string) - Sort by: "TIMESTAMP", "TOKENS", "CASH" * `sortDirection` (optional, string) - Sort direction: "ASC" or "DESC" * `side` (optional, string) - Trade side: "BUY" or "SELL" ### Example Request[](https://developer.probable.markets/api/orderbook-api/data#example-request) curl "https://api.probable.markets/public/api/v1/activity?user=0x1234...&limit=100&offset=0&sortBy=TIMESTAMP&sortDirection=DESC" ### Example Response[](https://developer.probable.markets/api/orderbook-api/data#example-response) [\ {\ "proxyWallet": "0x1234...",\ "timestamp": 1766021317660,\ "conditionId": "0x2019c8f7a5614febc00d175f1774ff9d9ffb0c5a6476fb277d64af3e2a90f9f6",\ "type": "TRADE",\ "size": 4.34,\ "usdcSize": 2.9946,\ "transactionHash": "0xfdb33dbfbe3dc88b43bfec4c18e484bd3a4bbd5602ef14bb5811a1ea82bfc0c0",\ "price": 0.69,\ "asset": "11800194545320447162805717721654917296903656967731164403423073642765210545273",\ "side": "BUY",\ "outcomeIndex": 1,\ "title": "Will the Grizzlies win against the Timberwolves?",\ "slug": "will-grizzlies-win-vs-timberwolves-2025-12-17",\ "icon": "",\ "eventSlug": "nba-grizzlies-vs-timberwolves-dec-17-2025",\ "outcome": "MIN",\ "name": "",\ "pseudonym": "",\ "bio": "",\ "profileImage": "",\ "profileImageOptimized": ""\ }\ ] * * * Current Position[](https://developer.probable.markets/api/orderbook-api/data#current-position) ------------------------------------------------------------------------------------------------- Get user's current positions. **Endpoint:** `GET /public/api/v1/position/current` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/data#query-parameters-1) * `user` (required, string) - User address * `limit` (optional, number) - Maximum number of results * `eventId` (optional, number) - Filter by event ID ### Example Request[](https://developer.probable.markets/api/orderbook-api/data#example-request-1) curl "https://api.probable.markets/public/api/v1/position/current?user=0x1234...&limit=100" Or filter by event ID: curl "https://api.probable.markets/public/api/v1/position/current?eventId=115&user=0x1234..." ### Example Response[](https://developer.probable.markets/api/orderbook-api/data#example-response-1) [\ {\ "asset": "11800194545320447162805717721654917296903656967731164403423073642765210545273",\ "conditionId": "0xd25e8f124e6b6577bd6a5731f33c2d327a0e5c320f2d22a5f6f5196688de88ed",\ "size": 4.34,\ "avgPrice": 0.69,\ "initialValue": 3.9744,\ "currentValue": 0,\ "cashPnl": -2.9946,\ "percentPnl": -100,\ "totalBought": 5.76,\ "realizedPnl": -2.4261999999999997,\ "percentRealizedPnl": -61.045692431561996,\ "curPrice": 0,\ "redeemable": true,\ "mergeable": false,\ "title": "Will the Grizzlies win against the Timberwolves?",\ "slug": "will-grizzlies-win-vs-timberwolves-2025-12-17",\ "icon": "",\ "eventSlug": "nba-grizzlies-vs-timberwolves-dec-17-2025",\ "outcome": "MIN",\ "outcomeIndex": 1,\ "oppositeOutcome": "MEM",\ "oppositeAsset": "106808096526227578757866083311477692286787530503432408976144301670100489402587",\ "endDate": "2025-12-17 21:00:00+00",\ "negativeRisk": false\ }\ ] * * * Profit and Loss (P&L)[](https://developer.probable.markets/api/orderbook-api/data#profit-and-loss-pl) -------------------------------------------------------------------------------------------------------- Get profit and loss data for a user. **Endpoint:** `GET /public/api/v1/pnl` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/data#query-parameters-2) * `user_address` (required, string) - User address ### Example Request[](https://developer.probable.markets/api/orderbook-api/data#example-request-2) curl "https://api.probable.markets/public/api/v1/pnl?user_address=0x1234..." ### Example Response[](https://developer.probable.markets/api/orderbook-api/data#example-response-2) [\ {\ "t": 1766407351099,\ "p": -2.1762\ },\ {\ "t": 1766410951099,\ "p": -2.1762\ },\ {\ "t": 1766414551099,\ "p": -2.1762\ }\ ] --- # Creating a Proxy Wallet | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/proxy-wallet#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Proxy Wallet On this page Chevron Right Before interacting with the Orderbook API, users must create a proxy wallet from their Externally Owned Account (EOA). This guide shows you how to create a proxy wallet using TypeScript and Viem. Overview[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#overview) ----------------------------------------------------------------------------------------- The proxy wallet is a smart contract wallet that acts as an intermediary between your EOA and the Orderbook API. All API interactions should use the proxy wallet address, not your EOA address. **Proxy Wallet Factory Contract:** * **Address:** `0xB99159aBF0bF59a512970586F38292f8b9029924` * **Network:** BSC (Binance Smart Chain) * **Chain ID:** 56 Prerequisites[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#prerequisites) --------------------------------------------------------------------------------------------------- Install the required dependencies: npm install viem Step-by-Step Guide[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-by-step-guide) ------------------------------------------------------------------------------------------------------------- ### Step 1: Setup Viem Client[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-1-setup-viem-client) First, create a wallet client connected to BSC: import { createWalletClient, http, custom } from 'viem'; import { bsc } from 'viem/chains'; // For browser environments (MetaMask, etc.) const walletClient = createWalletClient({ chain: bsc, transport: custom(window.ethereum), }); // For Node.js environments with private key import { privateKeyToAccount } from 'viem/accounts'; const account = privateKeyToAccount('0x...' as `0x${string}`); const walletClient = createWalletClient({ account, chain: bsc, transport: http(), }); ### Step 2: Get Your EOA Address[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-2-get-your-eoa-address) // For browser environments const [address] = await walletClient.getAddresses(); console.log('EOA Address:', address); // For Node.js with private key const eoaAddress = account.address; console.log('EOA Address:', eoaAddress); ### Step 3: Proxy Wallet Factory ABI[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-3-proxy-wallet-factory-abi) The proxy wallet factory contract uses the following interface: const PROXY_WALLET_FACTORY_ABI = [\ {\ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],\ name: 'computeProxyAddress',\ outputs: [{ internalType: 'address', name: '', type: 'address' }],\ stateMutability: 'view',\ type: 'function',\ },\ {\ inputs: [\ { internalType: 'address', name: 'paymentToken', type: 'address' },\ { internalType: 'uint256', name: 'payment', type: 'uint256' },\ { internalType: 'address payable', name: 'paymentReceiver', type: 'address' },\ {\ components: [\ { internalType: 'uint8', name: 'v', type: 'uint8' },\ { internalType: 'bytes32', name: 'r', type: 'bytes32' },\ { internalType: 'bytes32', name: 's', type: 'bytes32' },\ ],\ internalType: 'struct SafeProxyFactory.Sig',\ name: 'createSig',\ type: 'tuple',\ },\ ],\ name: 'createProxy',\ outputs: [],\ stateMutability: 'nonpayable',\ type: 'function',\ },\ {\ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],\ name: 'getSalt',\ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\ stateMutability: 'pure',\ type: 'function',\ },\ ] as const; ### Step 4: Compute and Check Proxy Wallet Address[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-4-compute-and-check-proxy-wallet-address) The proxy wallet address is deterministically computed from your EOA address. First, compute the address and check if it already exists: import { createPublicClient } from 'viem'; const publicClient = createPublicClient({ chain: bsc, transport: http(), }); const PROXY_WALLET_FACTORY_ADDRESS = '0xB99159aBF0bF59a512970586F38292f8b9029924' as const; async function computeProxyAddress(eoaAddress: `0x${string}`): Promise<`0x${string}`> { const proxyAddress = await publicClient.readContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: PROXY_WALLET_FACTORY_ABI, functionName: 'computeProxyAddress', args: [eoaAddress], }); return proxyAddress; } async function proxyWalletExists(proxyAddress: `0x${string}`): Promise { try { const code = await publicClient.getBytecode({ address: proxyAddress }); // If code exists and is not empty, the wallet is deployed return code !== undefined && code !== '0x' && code.length > 2; } catch (error) { return false; } } // Compute and check proxy wallet const proxyAddress = await computeProxyAddress(eoaAddress); const exists = await proxyWalletExists(proxyAddress); if (exists) { console.log('Proxy wallet already exists:', proxyAddress); // Use existing wallet } else { console.log('Proxy wallet not deployed yet:', proxyAddress); console.log('Creating proxy wallet...'); } ### Step 5: Create Proxy Wallet Signature[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-5-create-proxy-wallet-signature) The `createProxy` function requires a signature. You need to sign an EIP-712 message. First, get the domain separator and create the signature: import { encodeAbiParameters, keccak256, toBytes, recoverMessageAddress } from 'viem'; async function createProxySignature( eoaAddress: `0x${string}`, paymentToken: `0x${string}`, payment: bigint, paymentReceiver: `0x${string}` ): Promise<{ v: number; r: `0x${string}`; s: `0x${string}` }> { // Get domain separator from contract const domainSeparator = await publicClient.readContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: [\ {\ inputs: [],\ name: 'domainSeparator',\ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\ stateMutability: 'view',\ type: 'function',\ },\ ], functionName: 'domainSeparator', }); // Get CREATE_PROXY_TYPEHASH const createProxyTypehash = await publicClient.readContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: [\ {\ inputs: [],\ name: 'CREATE_PROXY_TYPEHASH',\ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\ stateMutability: 'view',\ type: 'function',\ },\ ], functionName: 'CREATE_PROXY_TYPEHASH', }); // Encode the struct hash // CREATE_PROXY_TYPEHASH = keccak256("CreateProxy(address user,address paymentToken,uint256 payment,address paymentReceiver)") // structHash = keccak256(abi.encode(CREATE_PROXY_TYPEHASH, user, paymentToken, payment, paymentReceiver)) const structHash = keccak256( encodeAbiParameters( [\ { type: 'bytes32' }, // CREATE_PROXY_TYPEHASH\ { type: 'address' }, // user\ { type: 'address' }, // paymentToken\ { type: 'uint256' }, // payment\ { type: 'address' }, // paymentReceiver\ ], [createProxyTypehash, eoaAddress, paymentToken, payment, paymentReceiver] ) ); // Create the message to sign: keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)) const message = keccak256( encodeAbiParameters( [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }], [\ '0x1901' as `0x${string}`, // EIP-191 prefix\ domainSeparator,\ structHash,\ ] ) ); // Sign the message const signature = await walletClient.signMessage({ message: { raw: toBytes(message) }, }); // Split signature into v, r, s const r = `0x${signature.slice(2, 66)}` as `0x${string}`; const s = `0x${signature.slice(66, 130)}` as `0x${string}`; const v = parseInt(signature.slice(130, 132), 16); return { v, r, s }; } ### Step 6: Create Proxy Wallet[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-6-create-proxy-wallet) Now create the proxy wallet with the signature: async function createProxyWallet( eoaAddress: `0x${string}`, paymentToken: `0x${string}` = '0x0000000000000000000000000000000000000000', // Zero address for no payment payment: bigint = 0n, paymentReceiver: `0x${string}` = '0x0000000000000000000000000000000000000000' // Zero address for no payment ): Promise<`0x${string}`> { // Compute the proxy address first const proxyAddress = await computeProxyAddress(eoaAddress); // Check if already exists if (await proxyWalletExists(proxyAddress)) { console.log('Proxy wallet already exists'); return proxyAddress; } // Create signature const createSig = await createProxySignature(eoaAddress, paymentToken, payment, paymentReceiver); // Create the proxy const hash = await walletClient.writeContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: PROXY_WALLET_FACTORY_ABI, functionName: 'createProxy', args: [paymentToken, payment, paymentReceiver, createSig], }); // Wait for transaction confirmation const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log('Transaction confirmed:', receipt.transactionHash); // Verify the wallet was created const exists = await proxyWalletExists(proxyAddress); if (!exists) { throw new Error('Failed to create proxy wallet'); } return proxyAddress; } // Create proxy wallet (no payment required) const proxyWalletAddress = await createProxyWallet(eoaAddress); console.log('Proxy wallet created:', proxyWalletAddress); ### Step 7: Complete Example[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#step-7-complete-example) Here's a complete example that computes the address, checks if it exists, and creates it if needed: import { createWalletClient, createPublicClient, http, custom, encodeAbiParameters, keccak256, toBytes, } from 'viem'; import { bsc } from 'viem/chains'; import { privateKeyToAccount } from 'viem/accounts'; const PROXY_WALLET_FACTORY_ADDRESS = '0xB99159aBF0bF59a512970586F38292f8b9029924' as const; const PROXY_WALLET_FACTORY_ABI = [\ {\ inputs: [{ internalType: 'address', name: 'user', type: 'address' }],\ name: 'computeProxyAddress',\ outputs: [{ internalType: 'address', name: '', type: 'address' }],\ stateMutability: 'view',\ type: 'function',\ },\ {\ inputs: [\ { internalType: 'address', name: 'paymentToken', type: 'address' },\ { internalType: 'uint256', name: 'payment', type: 'uint256' },\ { internalType: 'address payable', name: 'paymentReceiver', type: 'address' },\ {\ components: [\ { internalType: 'uint8', name: 'v', type: 'uint8' },\ { internalType: 'bytes32', name: 'r', type: 'bytes32' },\ { internalType: 'bytes32', name: 's', type: 'bytes32' },\ ],\ internalType: 'struct SafeProxyFactory.Sig',\ name: 'createSig',\ type: 'tuple',\ },\ ],\ name: 'createProxy',\ outputs: [],\ stateMutability: 'nonpayable',\ type: 'function',\ },\ {\ inputs: [],\ name: 'domainSeparator',\ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\ stateMutability: 'view',\ type: 'function',\ },\ {\ inputs: [],\ name: 'CREATE_PROXY_TYPEHASH',\ outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\ stateMutability: 'view',\ type: 'function',\ },\ ] as const; async function getOrCreateProxyWallet(eoaAddress: `0x${string}`): Promise<`0x${string}`> { // Setup clients const publicClient = createPublicClient({ chain: bsc, transport: http(), }); // For browser: use custom(window.ethereum) // For Node.js: use privateKeyToAccount const account = privateKeyToAccount('0x...' as `0x${string}`); const walletClient = createWalletClient({ account, chain: bsc, transport: http(), }); // Compute proxy address const proxyAddress = await publicClient.readContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: PROXY_WALLET_FACTORY_ABI, functionName: 'computeProxyAddress', args: [eoaAddress], }); // Check if wallet already exists const code = await publicClient.getBytecode({ address: proxyAddress }); if (code && code !== '0x' && code.length > 2) { console.log('Using existing proxy wallet:', proxyAddress); return proxyAddress; } // Create new proxy wallet console.log('Creating new proxy wallet...'); // Get domain separator and typehash const [domainSeparator, createProxyTypehash] = await Promise.all([\ publicClient.readContract({\ address: PROXY_WALLET_FACTORY_ADDRESS,\ abi: PROXY_WALLET_FACTORY_ABI,\ functionName: 'domainSeparator',\ }),\ publicClient.readContract({\ address: PROXY_WALLET_FACTORY_ADDRESS,\ abi: PROXY_WALLET_FACTORY_ABI,\ functionName: 'CREATE_PROXY_TYPEHASH',\ }),\ ]); // Prepare payment parameters (zero for no payment) const paymentToken = '0x0000000000000000000000000000000000000000' as `0x${string}`; const payment = 0n; const paymentReceiver = '0x0000000000000000000000000000000000000000' as `0x${string}`; // Create struct hash const structHash = keccak256( encodeAbiParameters( [\ { type: 'bytes32' },\ { type: 'address' },\ { type: 'address' },\ { type: 'uint256' },\ { type: 'address' },\ ], [createProxyTypehash, eoaAddress, paymentToken, payment, paymentReceiver] ) ); // Create message hash const message = keccak256( encodeAbiParameters( [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }], ['0x1901' as `0x${string}`, domainSeparator, structHash] ) ); // Sign message const signature = await walletClient.signMessage({ message: { raw: toBytes(message) }, }); // Split signature const r = `0x${signature.slice(2, 66)}` as `0x${string}`; const s = `0x${signature.slice(66, 130)}` as `0x${string}`; const v = parseInt(signature.slice(130, 132), 16); // Create proxy const hash = await walletClient.writeContract({ address: PROXY_WALLET_FACTORY_ADDRESS, abi: PROXY_WALLET_FACTORY_ABI, functionName: 'createProxy', args: [paymentToken, payment, paymentReceiver, { v, r, s }], }); // Wait for confirmation const receipt = await publicClient.waitForTransactionReceipt({ hash }); console.log('Proxy wallet created in transaction:', receipt.transactionHash); // Verify creation const newCode = await publicClient.getBytecode({ address: proxyAddress }); if (!newCode || newCode === '0x' || newCode.length <= 2) { throw new Error('Failed to create proxy wallet'); } console.log('Proxy wallet address:', proxyAddress); return proxyAddress; } // Usage const eoaAddress = '0x...' as `0x${string}`; const proxyWallet = await getOrCreateProxyWallet(eoaAddress); console.log('Proxy wallet ready:', proxyWallet); Important Notes[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#important-notes) ------------------------------------------------------------------------------------------------------- 1. **Gas Fees**: Creating a proxy wallet requires a transaction on BSC, so you'll need BNB for gas fees. 2. **One Wallet Per EOA**: Each EOA can only have one proxy wallet. The address is deterministically computed, so calling `computeProxyAddress` will always return the same address for the same EOA. 3. **Address Usage in API**: * **Authentication (`prob_address`)**: Always use your **EOA address** * **Order `maker` field**: Use your **proxy wallet address** * **Order `signer` field**: Use your **EOA address** (signs the order) * **Order `owner` field**: Use your **proxy wallet address** 4. **Deterministic Address**: The proxy wallet address is deterministically computed from your EOA address using `computeProxyAddress`. This means the address is predictable and can be computed before deployment. 5. **Signature Required**: Creating a proxy wallet requires an EIP-712 signature from your EOA. The signature authorizes the creation of the proxy wallet. Next Steps[](https://developer.probable.markets/api/orderbook-api/proxy-wallet#next-steps) --------------------------------------------------------------------------------------------- Once you have your proxy wallet address, proceed to the [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) to learn how to authenticate and interact with the Orderbook API. --- # Orderbook Data | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/orderbook#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Orderbook Data On this page Chevron Right Endpoints for accessing Central Limit Order Book data including prices, order books, and historical data. Get Price[](https://developer.probable.markets/api/orderbook-api/orderbook#get-price) ---------------------------------------------------------------------------------------- Get the current price for a specific token. **Endpoint:** `GET /public/api/v1/price` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orderbook#query-parameters) * `token_id` (required, string) - CTF token ID * `side` (required, string) - "BUY" or "SELL" ### Example Request[](https://developer.probable.markets/api/orderbook-api/orderbook#example-request) curl "https://api.probable.markets/public/api/v1/price?token_id=0xabc123...&side=BUY" ### Example Response[](https://developer.probable.markets/api/orderbook-api/orderbook#example-response) { "price": "0.65" } * * * Get Prices[](https://developer.probable.markets/api/orderbook-api/orderbook#get-prices) ------------------------------------------------------------------------------------------ Get prices for multiple tokens in a single request. **Endpoint:** `POST /public/api/v1/prices` ### Request Body[](https://developer.probable.markets/api/orderbook-api/orderbook#request-body) [\ {\ "token_id": "0xabc123...",\ "side": "BUY"\ },\ {\ "token_id": "0xdef456...",\ "side": "SELL"\ }\ ] ### Example Request[](https://developer.probable.markets/api/orderbook-api/orderbook#example-request-1) curl -X POST "https://api.probable.markets/public/api/v1/prices" \ -H "Content-Type: application/json" \ -d '[\ {\ "token_id": "0xabc123...",\ "side": "BUY"\ },\ {\ "token_id": "0xdef456...",\ "side": "SELL"\ }\ ]' ### Example Response[](https://developer.probable.markets/api/orderbook-api/orderbook#example-response-1) { "0xabc123...": { "BUY": "0.65", "SELL": "0.60" }, "0xdef456...": { "BUY": "0.45", "SELL": "0.40" } } * * * Get Midpoint[](https://developer.probable.markets/api/orderbook-api/orderbook#get-midpoint) ---------------------------------------------------------------------------------------------- Get the midpoint price between bid and ask for a token. **Endpoint:** `GET /public/api/v1/midpoint` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orderbook#query-parameters-1) * `token_id` (required, string) - CTF token ID ### Example Request[](https://developer.probable.markets/api/orderbook-api/orderbook#example-request-2) curl "https://api.probable.markets/public/api/v1/midpoint?token_id=0xabc123..." ### Example Response[](https://developer.probable.markets/api/orderbook-api/orderbook#example-response-2) { "mid": "0.625" } * * * Get Order Book[](https://developer.probable.markets/api/orderbook-api/orderbook#get-order-book) -------------------------------------------------------------------------------------------------- Get the complete order book (bids and asks) for a token. **Endpoint:** `GET /public/api/v1/book` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orderbook#query-parameters-2) * `token_id` (required, string) - CTF token ID ### Example Request[](https://developer.probable.markets/api/orderbook-api/orderbook#example-request-3) curl "https://api.probable.markets/public/api/v1/book?token_id=0xabc123..." ### Example Response[](https://developer.probable.markets/api/orderbook-api/orderbook#example-response-3) { "market": "BTC-USD", "asset_id": "0xabc123...", "timestamp": "1705312200", "hash": "0xdef456...", "bids": [\ {\ "price": "0.65",\ "size": "1000"\ },\ {\ "price": "0.64",\ "size": "500"\ }\ ], "asks": [\ {\ "price": "0.66",\ "size": "800"\ },\ {\ "price": "0.67",\ "size": "1200"\ }\ ], "min_order_size": "0.01", "tick_size": "0.001", "neg_risk": false } * * * Price History[](https://developer.probable.markets/api/orderbook-api/orderbook#price-history) ------------------------------------------------------------------------------------------------ Get historical price data for a token. **Endpoint:** `GET /public/api/v1/prices-history` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/orderbook#query-parameters-3) * `market` (required, string) - Market identifier (asset id) * `startTs` (optional, number) - Start timestamp * `endTs` (optional, number) - End timestamp * `interval` (optional, string) - Time interval: "max", "1m", "1h", "6h", "1d", "1w" * `fidelity` (optional, number) - Data fidelity level ### Example Request[](https://developer.probable.markets/api/orderbook-api/orderbook#example-request-4) curl "https://api.probable.markets/public/api/v1/prices-history?market=0xabc123...&interval=1h&startTs=1705312200&endTs=1705315800" ### Example Response[](https://developer.probable.markets/api/orderbook-api/orderbook#example-response-4) { "history": [\ {\ "t": 1705312200,\ "p": 0.65\ },\ {\ "t": 1705315800,\ "p": 0.66\ }\ ] } ### Interval Options[](https://developer.probable.markets/api/orderbook-api/orderbook#interval-options) * `max` - Maximum available data * `1m` - 1 minute intervals * `1h` - 1 hour intervals * `6h` - 6 hour intervals * `1d` - 1 day intervals * `1w` - 1 week intervals --- # Orderbook API | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/overview#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Overview On this page Chevron Right The Orderbook API provides comprehensive endpoints for trading, authentication, and data access. **Base URL:** `https://api.probable.markets` **API Version:** 1.0.0 Overview[](https://developer.probable.markets/api/orderbook-api/overview#overview) ------------------------------------------------------------------------------------- This API allows you to: * Authenticate users with multi-level authentication (L1, L2) * Manage API keys * Place and manage orders * Access orderbook data (prices, order books, historical data) * Retrieve trade history and user data Authentication[](https://developer.probable.markets/api/orderbook-api/overview#authentication) ------------------------------------------------------------------------------------------------- The API uses a multi-level authentication system: * **L1 Authentication**: EIP-712 signature verification (for initial auth and API key generation) * **L2 Authentication**: HMAC signature with API key (for orderbook write operations) **All orderbook write operations require L2 authentication.** Documentation Structure[](https://developer.probable.markets/api/orderbook-api/overview#documentation-structure) ------------------------------------------------------------------------------------------------------------------- ### Getting Started[](https://developer.probable.markets/api/orderbook-api/overview#getting-started) * [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) - Complete walkthrough of L1/L2 authentication and submitting your first order ### API Reference[](https://developer.probable.markets/api/orderbook-api/overview#api-reference) #### 1\. Authentication[](https://developer.probable.markets/api/orderbook-api/overview#1-authentication) Endpoints for user authentication and API key management. * [Authentication API](https://developer.probable.markets/api/orderbook-api/authentication) - Authentication endpoints reference * [API Keys API](https://developer.probable.markets/api/orderbook-api/api-keys) - API key management endpoints reference #### 2\. Orderbook[](https://developer.probable.markets/api/orderbook-api/overview#2-orderbook) Endpoints for order management and orderbook data access. * [Orders API](https://developer.probable.markets/api/orderbook-api/orders) - Order management endpoints reference * [Orderbook Data API](https://developer.probable.markets/api/orderbook-api/orderbook) - Prices, order books, and historical data endpoints reference #### 3\. Data[](https://developer.probable.markets/api/orderbook-api/overview#3-data) Endpoints for retrieving trade history and user data. * [Trades API](https://developer.probable.markets/api/orderbook-api/trades) - Trade history endpoints reference * [User Data API](https://developer.probable.markets/api/orderbook-api/data) - User activity, positions, and P&L endpoints reference Quick Start[](https://developer.probable.markets/api/orderbook-api/overview#quick-start) ------------------------------------------------------------------------------------------- 1. **Start here:** [Getting Started Guide](https://developer.probable.markets/api/orderbook-api/getting-started) - Learn how to authenticate and submit orders 2. **Then explore:** [API Reference](https://developer.probable.markets/api/orderbook-api/authentication) - Detailed endpoint documentation --- # Trades API | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/trades#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu Trades On this page Chevron Right Endpoints for retrieving trade history and information. Get Trades[](https://developer.probable.markets/api/orderbook-api/trades#get-trades) --------------------------------------------------------------------------------------- Get trade history with cursor-based pagination. **Endpoint:** `GET /public/api/v1/trade/{chainId}` ### Path Parameters[](https://developer.probable.markets/api/orderbook-api/trades#path-parameters) * `chainId` (required, number) - Chain ID ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/trades#query-parameters) * `tokenId` (required, string) - CTF token ID (symbol) * `before` (optional, string) - Encoded cursor for time filtering (get trades before this time) * `after` (optional, string) - Encoded cursor for time filtering (get trades after this time) * `next_cursor` (optional, string) - Encoded cursor for pagination (next page) * `limit` (optional, number, default: 10) - Maximum number of trades to return ### Headers (L2 Authentication Required)[](https://developer.probable.markets/api/orderbook-api/trades#headers-l2-authentication-required) * `prob_address` - **EOA address** (signed by EOA) * `prob_signature` - HMAC signature * `prob_timestamp` - Unix timestamp * `prob_api_key` - API key * `prob_passphrase` - API passphrase ### Example Request[](https://developer.probable.markets/api/orderbook-api/trades#example-request) curl "https://api.probable.markets/public/api/v1/trade/56?tokenId=0xabc123...&limit=20" \ -H "prob_address: 0x1234..." \ -H "prob_signature: 0xabc123..." \ -H "prob_timestamp: 1705312200" \ -H "prob_api_key: pk_live_abc123xyz" \ -H "prob_passphrase: my-passphrase" ### Example Response[](https://developer.probable.markets/api/orderbook-api/trades#example-response) { "trades": [\ {\ "id": 12345,\ "orderId": 67890,\ "symbol": "BTC-USD",\ "price": "0.65",\ "qty": "1.0",\ "quoteQty": "0.65",\ "commission": "0.001",\ "commissionAsset": "USDC",\ "time": 1705312200000,\ "buyer": true,\ "maker": false,\ "counterpartyId": 11111\ }\ ], "next_cursor": "eyJ0aW1lIjoxNzA1MzEyMjAwMDAwfQ==" } ### Pagination[](https://developer.probable.markets/api/orderbook-api/trades#pagination) Use the `next_cursor` from the response to fetch the next page: curl "https://api.probable.markets/public/api/v1/trade/56?tokenId=0xabc123...&next_cursor=eyJ0aW1lIjoxNzA1MzEyMjAwMDAwfQ==" * * * Get Public Trades[](https://developer.probable.markets/api/orderbook-api/trades#get-public-trades) ----------------------------------------------------------------------------------------------------- Get public trade history (no authentication required). **Endpoint:** `GET /public/api/v1/trades` ### Query Parameters[](https://developer.probable.markets/api/orderbook-api/trades#query-parameters-1) * `user` (optional, string) - User Profile Address (0x-prefixed, 40 hex chars) * `limit` (optional, number, default: 100) - Maximum number of trades to return * `offset` (optional, number, default: 0) - Offset for pagination * `takerOnly` (optional, boolean, default: true) - Filter to taker trades only * `filterType` (optional, string) - Filter type: "CASH" or "TOKENS" (must be provided with filterAmount) * `filterAmount` (optional, number) - Filter amount (must be provided with filterType) * `market` (optional, string or array) - Comma-separated list of condition IDs. Mutually exclusive with eventId * `eventId` (optional, string or array) - Comma-separated list of event IDs. Mutually exclusive with market * `side` (optional, string) - Trade side: "BUY" or "SELL" ### Example Request[](https://developer.probable.markets/api/orderbook-api/trades#example-request-1) curl "https://api.probable.markets/public/api/v1/trades?user=0x1234...&limit=50&side=BUY" ### Example Response[](https://developer.probable.markets/api/orderbook-api/trades#example-response-1) [\ {\ "proxyWallet": "0x1234...",\ "side": "BUY",\ "asset": "USDC",\ "conditionId": "0xabc123...",\ "size": 1.0,\ "price": 0.65,\ "timestamp": 1705312200000,\ "title": "Will BTC exceed $100k?",\ "slug": "btc-100k",\ "icon": "https://...",\ "eventSlug": "btc-usd-2025-11",\ "outcome": "Yes",\ "outcomeIndex": 0,\ "name": "John Doe",\ "pseudonym": "trader123",\ "bio": "Crypto trader",\ "profileImage": "https://...",\ "profileImageOptimized": "https://...",\ "transactionHash": "0xdef456..."\ }\ ] --- # TypeScript SDK | Probable Developer [Skip to content](https://developer.probable.markets/api/orderbook-api/typescript-sdk#vocs-content) Search [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) Sun Moon [![Logo](https://developer.probable.markets/logo_dark.svg)![Logo](https://developer.probable.markets/logo.svg)](https://developer.probable.markets/) [API](https://developer.probable.markets/api/overview) Menu TypeScript SDK On this page Chevron Right This content has moved to the top-level **TypeScript SDK** section: * [TypeScript SDK Overview](https://developer.probable.markets/api/typescript-sdk/overview) The SDK (`@prob/clob`) provides a convenient way to interact with Probable’s APIs (order placement, market data, positions, and authenticated endpoints). Related resources[](https://developer.probable.markets/api/orderbook-api/typescript-sdk#related-resources) ------------------------------------------------------------------------------------------------------------- * [Installation](https://developer.probable.markets/api/typescript-sdk/installation) * [Quick Start](https://developer.probable.markets/api/typescript-sdk/quickstart) * [Orders](https://developer.probable.markets/api/typescript-sdk/orders) * [Fees](https://developer.probable.markets/api/typescript-sdk/fees) * [Market Data](https://developer.probable.markets/api/typescript-sdk/market-data) * [Positions](https://developer.probable.markets/api/typescript-sdk/positions) * [WebSocket](https://developer.probable.markets/api/typescript-sdk/websocket) * [Proxy Wallet](https://developer.probable.markets/api/typescript-sdk/proxy-wallet) ---