Getting Started
This guide walks you through the complete setup process: creating a proxy wallet, authenticating with L1/L2, and submitting orders.
Overview
All orderbook write operations (placing orders, canceling orders, etc.) require:
- Proxy Wallet - A smart contract wallet created from your EOA
- L2 Authentication - API credentials for authenticated requests
- Create Proxy Wallet - Set up a proxy wallet from your EOA (required for all users)
- Approve Tokens - Approve token spending allowances (required before trading)
- L1 Authentication - Get a nonce and authenticate with wallet signature
- Generate API Key - Use L1 credentials to generate L2 API key and secret
- L2 Authentication - Use API key and secret to sign requests with HMAC
- 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 for detailed instructions.
- Before placing orders, you must approve token spending. See the Token Approvals Guide for detailed instructions.
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.
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.
Important Address Usage:- Authentication (
prob_address): Always use your EOA address - Order
makerfield: Use your proxy wallet address - Order
signerfield: Use your EOA address
Step 0.5: 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.
Required Approvals:- USDT → CTF Token contract (for splitting/merging)
- USDT → CTF Exchange (for trading)
- CTF Tokens → CTF Exchange (for trading)
Step 1: L1 Authentication
L1 authentication uses EIP-712 signature verification with your wallet.
1.1 Get a Nonce
First, request a nonce from the API:
curl "https://api.probable.markets/public/api/v1/auth/nonce"{
"nonce": "abc123xyz",
"issuedAt": "2025-01-15T10:30:00Z"
}1.2 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
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
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
Once you're authenticated with L1, you can generate an API key for L2 authentication.
2.1 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 EOAprob_timestamp- Current Unix timestampprob_nonce- Nonce from step 1.1
2.2 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"Response:Note: Use your EOA address in
prob_addressfor authentication. The signature must be signed by the EOA.
{
"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)
L2 authentication uses HMAC-SHA256 to sign requests with your API key and secret.
3.1 Create HMAC Signature
The signature is created by hashing a combination of:
- Timestamp
- HTTP method (GET, POST, etc.)
- Request path
- Request body (if any)
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
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 timestampprob_api_key- Your API keyprob_passphrase- Your passphrase
Step 4: Submit an Order
Now you can use L2 credentials to place orders.
4.1 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
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
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:Response:
prob_addressheader: Use your EOA address- Order
makerfield: Use your proxy wallet address- Order
signerfield: Use your EOA address- Order
ownerfield: Use your proxy wallet address
{
"orderId": 12345,
"symbol": "BTC-USD",
"side": "BUY",
"status": "NEW",
...
}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
- Proxy Wallet Guide - Detailed proxy wallet creation guide
- Authentication Reference - Detailed authentication API specs
- API Keys Reference - API key management endpoints
- Orders Reference - Complete order management API