API Reference
Machine-readable OpenAPI spec
The full API surface is published as an OpenAPI 3.1 document served directly by the gateway:
- JSON (prod):
https://oracle-api.parti.com/openapi.json - YAML (prod):
https://oracle-api.parti.com/openapi.yaml - Staging:
https://oracle-gateway.pbcapps.dev/openapi.json
These endpoints are public — no API key, no Origin negotiation — and refresh on every gateway deploy. Use them for:
- Codegen:
npx @openapitools/openapi-generator-cli generate -i https://oracle-gateway.pbcapps.dev/openapi.json -g typescript-fetch -o ./client - Postman / Insomnia: import the JSON URL directly
- AI / agent tooling: point any OpenAPI-aware agent at the JSON URL and it gets the full route + schema set without scraping HTML
Quick sanity check:
curl -s https://oracle-gateway.pbcapps.dev/openapi.json | jq '.info.version, (.paths | length)'
If your sandbox can't reach the host, see Getting Started → Sandbox network access.
Authenticated write endpoints (EIP-712)
Writes are signed client-side: every action is an EIP-712 typed struct
signed under the PartiVault domain with your EVM key, and the request carries
the resulting 65-byte signature. There is no managed signer service — you hold
your own key. Orders additionally require the session cookie from
/v1/builders/register. See Authentication.
POST /v1/builders/register
Sign the EIP-712 SessionBootstrap{user,timestamp} struct. Issues the session
cookie and returns a stable builder_api_key.
Request:
{
"user": "0x7a3f…",
"name": "my-bot",
"signature": "0x<65-byte EIP-712 signature>",
"timestamp": 1777500000
}
Response (also sets Set-Cookie: parti_oracle_session=…; HttpOnly):
{"api_key": "a1b2c3d4-…", "wallet": "0x7a3f…", "name": "my-bot"}
POST /v1/orders
Auth: session cookie + a 65-byte EIP-712 Order signature.
Submit a signed order. This is the primary trading endpoint.
Request:
{
"market_id": "abc123def456...",
"user": "0x7a3f…",
"side": "buy",
"outcome": "yes",
"price": 6500,
"size": 100,
"order_type": "gtc",
"signature": "0x<65-byte EIP-712 Order signature>",
"nonce": 1777500000123,
"builder_api_key": "a1b2c3d4-…"
}
| Field | Type | Description |
|---|---|---|
market_id |
string | 64-char hex or slug (see Market IDs) |
user |
string | your lowercase 0x address |
side |
"buy" or "sell" |
|
outcome |
"yes" or "no" |
|
price |
int | 1-9999 basis points (5000 = $0.50) |
size |
int | Number of contracts |
order_type |
string | "gtc", "ioc", "fok", "post_only" |
signature |
string | 65-byte EIP-712 signature over the Order struct — required |
nonce |
int | per-user monotonic timestamp nonce |
builder_api_key |
string | optional fee attribution |
Response:
{
"order_id": 42,
"market_id": "abc123...",
"fills": [
{
"quantity": 50,
"price": 6200,
"taker_fee": 7,
"maker_rebate": 0,
"builder_fee": 31,
"builder_api_key": "a1b2c3d4-…",
"settlement_type": "mint",
"outcome": "yes",
"taker_side": "buy",
"maker_side": "sell",
"maker": "0x0000000000000000000000000000000000000000",
"taker": "0x7a3f…",
"maker_order_id": 10,
"taker_order_id": 42,
"timestamp": 1700000000
}
],
"remaining": 50
}
!!! note "Fill Field Naming"
Live order fills returned by /v1/orders use quantity and timestamp.
The historical /v1/trades/{user} and /v1/markets/{id}/trades REST endpoints return size and time instead.
Client code should handle both forms when unifying data sources.
Market Orders
To place a "market" order (fill immediately at best available price), use ioc with an extreme price:
- Market Buy:
{ "side": "buy", "price": 9999, "order_type": "ioc" }— fills at best asks - Market Sell:
{ "side": "sell", "price": 100, "order_type": "ioc" }— fills at best bids
The remaining field in the response indicates any unfilled portion (which is automatically cancelled for IOC orders).
The signed Order struct
The EIP-712 Order signature covers these fields, under the PartiVault
domain ({ name: 'PartiVault', version: '1', chainId, verifyingContract }):
market bytes32 market-id slot (see Market IDs below)
user address your 0x EVM wallet
outcome uint8 (0 = yes, 1 = no)
side uint8 (0 = buy, 1 = sell)
price uint256 basis points (1..9999)
size uint256 contracts
nonce uint256 per-user monotonic timestamp nonce
chainId + verifyingContract must match the gateway's domain for the
environment you point at, or the signature recovers to the wrong address and
the gateway returns 403 invalid_signature.
POST /v1/orders/cancel and /v1/orders/cancel-all
Auth: session cookie only — no signature. There is no CancelAll
EIP-712 struct; the engine resolves the acting user from the cookie and
owner-checks each resting order.
// POST /v1/orders/cancel — single order
{"market_id": "abc...", "order_id": 42, "user": "0x7a3f…"}
// POST /v1/orders/cancel-all — optional market_id to scope to one market
{"user": "0x7a3f…", "market_id": "abc...", "builder_api_key": "a1b2c3d4-…"}
Carry the builder_api_key on cancel-all so the engine skips the short
user-halt meant for the browser "Cancel All" button.
POST /v1/positions/redeem-sets
Auth: session cookie + a 65-byte EIP-712 RedeemSets{user,market,nonce}
signature. Redeems matched YES+NO sets back to collateral.
POST /v1/withdraw-signed
Auth: a 65-byte EIP-712 Withdraw{user,recipient,amount,nonce,deadline}
signature with chain:'robinhood'. The nonce is the sequential on-chain
vault nonce (vault.nonces(user)), not the order timestamp nonce — see
Deposits → Withdraw.
{
"user": "0x7a3f…",
"recipient": "0x7a3f…",
"amount": "10000000",
"nonce": 0,
"deadline": 1799000000,
"signature": "0x<65-byte EIP-712 Withdraw signature>",
"chain": "robinhood"
}
Gateway Endpoints (Public, No Auth)
Read market data directly from the gateway. No API key needed.
GET /v1/markets
Every entry has event_id + outcomes[]. Binary = 1 outcome. Multi = N outcomes. Use market_id from outcomes when placing orders.
{
"markets": [
{
"event_id": "abc123...",
"question": "Will BTC reach $200k?",
"category": {"name": "crypto", "sub": "bitcoin"},
"status": "active",
"fee_bps": 25,
"expiry": 1798761600,
"outcomes": [
{"label": "Yes", "market_id": "def456...", "yes_price": 7200, "yes_bid": 7000, "yes_ask": 7400, "mark_bps": 7150}
]
}
]
}
Each outcome carries a server-refreshed oracle fair value as mark_bps
(de-vigged OpticOdds for sports, Pyth-implied for crypto) — the anchor market
makers quote against.
GET /v1/events
List all events (multi-outcome markets grouped under one question).
GET /v1/events/{id}
Event details with per-outcome prices.
GET /v1/markets/{id}
Single market with full price data, including per-outcome mark_bps.
GET /v1/markets/{id}/book
Full order book snapshot (yes/no bids and asks).
GET /v1/markets/{id}/trades?limit=100&before=500
Trade history for a market. Cursor-paginated, newest first.
GET /v1/markets/{id}/candles?interval=5m&from=0&to=9999999999
OHLCV candlestick data. Intervals: 1m, 5m, 15m, 1h, 1d.
GET /v1/balance/{address}
User's balance (available, locked) in micro-USDG. {address} is the lowercase 0x address.
GET /v1/position/{market_id}/{address}
User's position in a market. The gateway returns { outcome, size, yes, no, avg_price } — yes/no are the raw leg counts.
GET /v1/trades/{address}
User's trade history across all markets.
GET /v1/fees
Public fee schedule -- all categories, rates, and builder info.
Market IDs (hex vs slug)
Two encodings are accepted everywhere a market_id appears:
- 64-char hex — used verbatim as the
bytes32market slot in the signed struct. - Slug string (e.g.
oracle-btc-5m-1700000000-0) — the slot isSHA-256(utf8(market_id)).
Both resolve to the same bytes32 the gateway and engine use when verifying the signature.
Order Types
| Type | Behavior |
|---|---|
gtc |
Good-til-cancelled. Rests unmatched portion on the book. |
ioc |
Immediate-or-cancel. Fills what it can, cancels the rest. |
fok |
Fill-or-kill. Must fill entirely or is rejected. |
post_only |
Must rest as maker. Rejected if it would match immediately. |
Price Format
All prices are in basis points (1-9999): - 5000 = $0.50 (50% probability) - 7500 = $0.75 (75% probability) - 100 = $0.01 (1% probability)
Balance Format
All balances in micro-USDG (6 decimals): - 1,000,000 = $1.00 - 10,000,000 = $10.00