Documentation Index
Fetch the complete documentation index at: https://docs.outcome.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Authentication Flow
-
Request Nonce message
Obtain a message from the auth nonce endpoint
-
Sign the message using SIWE
The user signs the message with their wallet to prove ownership of the address.
-
Exchange the signed message for a JWT access token
Submit the signed message to receive a JWT access token.
-
Use the token for all authenticated requests
Include the JWT in the
Authorization header for subsequent API calls.
-
After completing authentication flow
Deposite your funds on your contract address, use user details api to get contract address
Rate Limit
Global Rate Limit
Maximum 150 requests per second allowed
Order Creation Rate Limit
Maximum 10 orders per second allowed with networking slowdown
Authentication API
Nonce API
Request Nonce: The client first requests a unique nonce from the backend. This nonce prevents
replay attacks and must be included in the signed message.
Endpoint
POST /api/auth/nonce
Response Type
type Response = {
nonce?: string
error?: string
}
Sign In API
Using the nonce from Step 1, the client creates a SIWE message and asks the wallet to sign it.
Send the signed message details to the backend to authenticate the user.
Endpoint
POST /api/auth/signin
Body
| Field | Type | Required | Description |
|---|
address | string | Yes | Wallet address used to sign the message |
signature | string | Yes | Signature generated by the wallet |
issuedAt | string(ISO 8601) | Yes | Timestamp when the message was signed |
domain | string | Yes | Domain requesting authentication |
uri | string | Yes | URI of the requesting application |
Response Type
type Response = {
token: string
is_firstTime: boolean
}
| Field | Type | Description |
|---|
token | string | JWT used for authenticated requests |
is_firstTime | boolean | Indicates if this is the user’s first login |
SIWE SignIn Code Snippet
import { SiweMessage } from 'siwe'
const message = new SiweMessage({
domain,
address,
statement: 'Welcome to Outcome market! Sign to connect.',
uri,
version: '1',
chainId,
nonce //from nonce api
})
const siweMessageString = message.prepareMessage()
Authenticated API Rules
All endpoints below require:
Authorization: Bearer <token>
Notes
userAddress is extracted from the JWT
Enable Trading
Enable Trading allows the outcome market smart contracts to move your tokens on your behalf.
It’s a one-time approval that lets the platform spend ERC20 Tokens.
Example Code
import { ethers } from 'ethers'
const provider = new ethers.BrowserProvider(window.ethereum)
const signer = await provider.getSigner()
const response = await axios.get('/api/enable-trading/signature', {
headers: {
Authorization: Bearer<token>
}
})
const signature = await signer.signMessage(ethers.getBytes(messageHash))
const response = await axios.post(
'/api/enable-trading',
{
signature
},
{
headers: {
Authorization: Bearer<token>
}
}
)
Enable Trading Signature
Endpoint
GET /api/enable-trading/signature
Response Type
type Response = {
success: boolean
messageHash: string
error?: string
}
Enable Trade
Endpoint
POST /api/enable-trading
Body Parameters
| Name | Type | Required | Description |
|---|
signature | string | Yes | |
Example Response
Response Type
type Response = {
success: boolean
data?: { transactionHash: string }
error?: string
}
User Details API
Endpoint
POST /api/me
Response Type
type User = {
id: string
public_address: string
username: string
contract_address: string
avatar_url: string
created_at: string // ISO date string
updated_at: string // ISO date string
email: string | null
auth_nonce: string | null
order_nonce: number
enable_trading_hash: string
trading_enabled: boolean
}
Balance API
Get USER Balance
Endpoint
GET /api/realtime/user/balance
Example Response
{
"balance": {
"available": "1573",
"locked": "0",
"total": "1573"
}
}
Balance Object Definition
| Field | Type | Description |
|---|
available | string | On Chain balance - Open orders amount |
locked | string | Open orders amount |
total | string | On Chain balance |
Get Asset Balance
Endpoint
GET /api/realtime/user/assetbalance
Query Parameters
| Name | Type | Required | Description |
|---|
marketId | number | Yes | Market ID |
Example Response
{
"balance": {
"available": "1573",
"locked": "0",
"total": "1573"
}
}
Asset Balance Object Definition
| Field | Type | Description |
|---|
available | string | On Chain Asset balance - Open orders amount |
locked | string | Open orders amount |
total | string | On Chain Asset balance |
User Outcomes
Endpoint
POST /api/me/outcomes
Response Type
type Outcome = {
id: number
eventId: number
outcome: string
time: string // ISO 8601 timestamp
contract: string
tokenType: 'YES' | 'NO'
price: string
size: string
pnl: string
category: 'CRYPTO' | 'SPORTS'
feedType: 'PYTH' | 'SBAN'
action: 'CLOSED' | 'CLAIMED' | ''
txnHash: string | null
teamHash: string
singleEvent: boolean
}
| Field | Type | Description |
|---|
id | number | Unique identifier of the outcome record |
eventId | number | Associated event ID |
outcome | "Won" | "Lose" | Result of the position |
time | string (ISO 8601) | Event resolution timestamp |
contract | string | Contract or market name |
tokenType | "YES" | "NO" | Side/token held by the user |
price | string | Entry price per token |
size | string | Quantity of tokens |
pnl | string | Profit or loss for this outcome |
action | string | user claimed or not |
txnHash | string | claimed txn hash |
Claim Tokens API
Endpoint
GET /api/markets/marketId/claim
Response Type
type Response = {
success: boolean,
message: string,
transaction: {
hash: 0xstring,
},
error?: string
}
Market ID Convention
| Outcome | Market ID |
|---|
| YES | EventID × 2 |
| NO | EventID × 2 + 1 |
Order APIs
Create Order
Place a new order.
Rate Limit
Maximum 10 orders per second allowed with networking slowdown
Endpoint
POST /api/orders
Payload Type
type CreateOrderPayload = {
market_id: string
side: 'LIMIT' | 'MARKET'
OrderSide: 'BUY' | 'SELL'
quantity: string
limit_price: string // required if OrderType == "LIMIT"
asset: string
slippage: string
}
Body Parameters
| Name | Type | Required | Description |
|---|
market_id | number | Yes | YES = EventID × 2, NO = EventID × 2 + 1 |
quantity | string | Yes | Integer quantity |
limit_price | string | Yes | Price per unit (0.0 - 1.0) |
OrderSide | "BUY" | "SELL" | Yes | Order side |
OrderType | "LIMIT" | "MARKET" | Yes | Order execution type |
asset | "YES" | "NO" | Yes | Outcome asset (YES or NO) |
slippage | string | No | amount of slippage between 0 to 20 cents |
Cancel Order
Endpoint
POST /api/orders/orderId/cancel
Parameters
| Name | Type | Required | Description |
|---|
orderId | string | Yes | your order id |
Cancel All Open Orders
Endpoint
POST /api/orders/cancel-all
Get Open Orders
Retrieve open and partially filled orders.
Endpoint
GET /api/realtime/openOrders
Response
{
success: boolean
data: {
orderId: string
marketId: string
quantity: string
price: string
side: string
status: string
created_at: string
}
;[]
}
Position APIs
Get User Positions
Retrieve current user positions across all markets.
Endpoint
GET /api/realtime/positions
Example Response Type
export type PositionsApiResponse = {
success: boolean
data: Position[]
}
export type Position = {
contract: string
size: string
entry_price: string
mark_price: string
position_value: string
pnl: string // e.g. "-117.98 (-34.83%)"
side: 'YES' | 'NO'
event_id: number
teamName: string | null
singleEvent: boolean
category: 'STOCK' | 'CRYPTO' | 'SPORTS'
}
Position Object Definition
| Field | Type | Description |
|---|
contract | string | Contract / market name |
size | string | Net position size |
entry_price | string | Average entry price |
mark_price | string (optional) | Current mark price |
position_value | string | Current position value |
pnl | string | PnL formatted as value (percent) |
side | "YES" | "NO" | Outcome side |
event_id | number | Event ID |
teamName | string | null | Sports team (if applicable) |
singleEvent | boolean | Single-outcome market |
category | string | CRYPTO, SPORTS, STOCK, COMMODITIES |
Important Notes
mark_price and pnl may be "NaN" if pricing data is unavailable
- YES and NO positions for the same event are returned separately
Trade History APIs
Get User Trade History
Retrieve paginated executed trades.
Endpoint
GET /api/realtime/tradeHistory
Query Parameters
| Name | Type | Description |
|---|
userAddress | string | user wallet address |
page | number | Default: 1 |
pageSize | number | Default: 20, Max: 100 |
Trade Object Definition
| Field | Type | Description |
|---|
id | string | Trade ID |
time | string (ISO 8601) | Execution time |
contract | string | Market name |
direction | string | e.g. Buy (Yes) |
price | number | Execution price |
size | string | Filled quantity |
tradeValue | string | price × size |
teamName | string | null | Sports team |
singleEvent | boolean | Single-outcome |
fee | string | Fee paid |
feeRate | string | Applied fee rate |
role | "Maker" | "Taker" | Liquidity role |
closedPNL | string | Realized PnL or ”—” |
Notes
price may include floating-point artifacts
closedPNL is populated only when a trade reduces exposure
Public Market Data APIs
Get Orderbook
Retrieve raw, non-aggregated orderbook data.
Endpoint
GET /api/realtime/orderbook/:marketId
Authentication: Not required
Market ID Convention
| Outcome | Market ID |
|---|
| YES | EventID × 2 |
| NO | EventID × 2 + 1 |
Orderbook Response Structure
{
"bids": [Order],
"asks": [Order],
"_meta": Meta
}
Order Object
| Field | Type | Description |
|---|
orderId | string | Unique order ID |
price | string | Limit price |
quantity | string | Remaining quantity |
userId | string | Maker wallet |
source | string | Liquidity source |
Metadata (_meta)
| Field | Type | Description |
|---|
dollarCap | number | Max dollar exposure |
syntheticEnabled | boolean | Synthetic liquidity flag |
syntheticNotional | number | null | Synthetic size |
timestamp | number | Server timestamp (ms) |
Notes
- Orders are not aggregated
- Best bid = highest bid price
- Best ask = lowest ask price
Event-Level Market Data
Events API
Endpoint
GET /api/realtime/events?page=1&pageSize=10&status=OPEN&sortBy=volume
Response Type
type Event = {
id: number
title: string
description: string
category: 'CRYPTO' | 'STOCK' | 'SPORTS'
subcategory: string
status: 'OPEN' | 'RESOLVED' | 'CLOSED'
image_url: string
tags: string
created_at: string // ISO 8601
updated_at: string // ISO 8601
start_time: string | null
end_time: string
rules: string
nickname: string
autoResolve: boolean
isMultiEvent: boolean
isPrimaryEvent: boolean
singleEvent?: boolean
operator: 'LT' | 'GT' | null
triggerPrice: string | null
pythPriceId: string | null
feedType: 'PYTH' | 'SBAN'
priceSymbol: string
provider: string | null
providerEventId: string | null
winningTokenId: number | null
txnHash: string | null
outcome: string | null
resolutionHash: string | null
resolutionTime: string | null
resolutionReason: string | null
leagueName: string | null
matchStatus: string | null
sportId: string | null
teamA: string | null
teamA_id: string | null
teamA_image: string | null
teamB: string | null
teamB_id: string | null
teamB_image: string | null
markets?: Market[]
yesMarketId?: number
noMarketId?: number
yesMarketPrice?: string
noMarketPrice?: string
yesPercent?: number
noPercent?: number
chance: string
priceVariation: string
volume: number
totalVolume: number
comment_count: number
isWatchlisted: boolean
}
export type Market = {
eventId: number
title: string
status: string
end_time: string
rules: string
marketIds: number[]
team_id: string
teamName: string
teamImage: string | null
seedOperator: string
chance: string
yesMarketPrice: string
noMarketPrice: string
winningTokenId: number | null
outcome: string | null
volume: number
priceVariation: string
}
Query Parameters
| Parameter | Type | Description |
|---|
category | string | Filter events by category (e.g. CRYPTO, STOCK, SPORTS) |
status | string | Filter events by status (e.g. OPEN, RESOLVED, CLOSED) |
subcategory | string | Filter events by subcategory (e.g. Hype, MEMES, SOCCER) |
search | string | Text search on event title or description |
address | string | Wallet address to personalize results (e.g. watchlisted events) |
page | number | Page number for pagination |
pageSize | number | Number of records per page |
sortBy | string | Field used for sorting (e.g. volume, end_time, created_at) |
sortOrder | "asc" | "desc" | Sort direction |
leagueName | string | Filter sports events by league name |
volume | number | Minimum total volume filter |
Get Event By Id
Endpoint
GET /api/realtime/events/:eventId
Response Type
type Event = {
id: number
title: string
description: string
category: 'CRYPTO' | 'STOCK' | 'SPORTS'
subcategory: string
status: 'OPEN' | 'RESOLVED' | 'CLOSED'
image_url: string
tags: string
created_at: string // ISO 8601
updated_at: string // ISO 8601
start_time: string | null
end_time: string
rules: string
nickname: string
autoResolve: boolean
isMultiEvent: boolean
isPrimaryEvent: boolean
singleEvent?: boolean
operator: 'LT' | 'GT' | null
triggerPrice: string | null
pythPriceId: string | null
feedType: 'PYTH' | 'SBAN'
priceSymbol: string
provider: string | null
providerEventId: string | null
winningTokenId: number | null
txnHash: string | null
outcome: string | null
resolutionHash: string | null
resolutionTime: string | null
resolutionReason: string | null
leagueName: string | null
matchStatus: string | null
matchStatus: string | null
sportId: string | null
teamA: string | null
teamA_id: string | null
teamA_image: string | null
teamB: string | null
teamB_id: string | null
teamB_image: string | null
markets?: Market[]
yesMarketId?: number
noMarketId?: number
yesMarketPrice?: string
noMarketPrice?: string
yesPercent?: number
noPercent?: number
chance: string
priceVariation: string
volume: number
totalVolume: number
comment_count: number
isWatchlisted: boolean
}
Get Sports Event By Id
Endpoint
GET /api/realtime/sports/:eventId
Response Type
SportsEvent {
title: string;
description: string;
category: "SPORTS";
subcategory: "SOCCER";
status: "OPEN" | "PAUSED" | "RESOLVED";
markets: Market[];
created_at: ISODateString;
updated_at: ISODateString;
tags: string;
image_url: string;
autoResolve: boolean;
operator: string | null;
pythPriceId: string | null;
triggerPrice: number | null;
winningTokenId: string | null;
txnHash: string;
resolutionHash: string | null;
start_time: ISODateString | null;
matchStartTime: ISODateString;
matchStatus: "NOT_STARTED" | "LIVE" | "FINISHED";
resolutionTime: ISODateString | null;
feedType: "SBAN";
priceSymbol: string;
provider: "NONN";
sportId: string;
leagueName: string;
comments: Comment[];
comment_count: number;
is_watchlisted: boolean;
totalVolume: string;
priceVariation: string;
yesPercent: number;
noPercent: number;
}
Market {
eventId: number;
title: string;
nickname: string;
end_time: ISODateString;
rules: string;
marketIds: number[];
team_id: string;
teamName: string;
teamImage: string;
seedOperator: "TEAMA" | "TEAMB" | "DRAW";
chance: string;
yesMarketPrice: string;
noMarketPrice: string;
volume: number | string;
winningTokenId: string | null;
outcome: "YES" | "NO" | null;
priceVariation: string;
}
Get Event Trades
Retrieve recent trades across all markets in an event.
Endpoint
GET /api/realtime/sports/:eventId
Response Type
type TradesApiResponse = {
success: boolean
data: {
trades: {
id: string
user: {
id: string
name: string
}
choice: 'YES' | 'NO'
side: 'BUY' | 'SELL'
price: number
size: number
time: string
}[]
totalCount: number
}
cached: boolean
}
Get Sports Event Trades
Retrieve recent trades across all markets in a sports event.
Endpoint
GET /api/realtime/sports/:eventId/trades
Response Type
type TradesApiResponse = {
success: boolean
data: {
trades: {
id: string
user: {
id: string
name: string
}
choice: 'YES' | 'NO'
side: 'BUY' | 'SELL'
price: number
size: number
time: string
}[]
totalCount: number
}
cached: boolean
}
Withdraw Funds
Example Code
import { ethers } from 'ethers'
// encode withdrawal calldata
const iface = new ethers.Interface(['function transfer(address recipient, uint256 amount)'])
const amountInWei = ethers.parseUnits(amount, 6)
const data = iface.encodeFunctionData('transfer', [recipient, amountInWei])
// create message hash
const messageHash = ethers.solidityPackedKeccak256(
['address', 'uint256', 'address', 'uint256', 'bytes', 'uint256'],
[userContractAddress, BigInt(chainId), USDT_ADDRESS, 0, data, nonce]
)
// sign message
const signature = await signer.signMessage(ethers.getBytes(messageHash))
const response = await axios.post(
'/api/me/withdraw',
{
amount,
recipient,
signature
},
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
Endpoint
POST /api/me/withdraw
Body
| Name | Type | Required | Description |
|---|
amount | string | Yes | amount of tokens to withdraw |
recipient | string | Yes | Your wallet EOA Address |
signature | string | Yes | Signed Message |