Documentation Index
Fetch the complete documentation index at: https://docs.adipredictstreet.com/llms.txt
Use this file to discover all available pages before exploring further.
Audience
This surface is for partners running off-platform copies of the trade
log — typically auditors and regulator-tech integrations. It is not
for retail wallet flows; for a single user’s own trades use
GET /api/me/trades.
Two endpoints:
GET /api/v1/partner/trades — incremental, cross-wallet trade feed.
GET /api/v1/partner/reconciliation/snapshot — window-aggregate cross-check.
Authentication
Both endpoints use API-key auth.
- Header:
X-Api-Key: ps_live_<keyId>_<secret>
- Required scope:
partner:trades:read
- The scope is read-only by design — admin refuses to issue a key
that mixes
partner:trades:read with any write scope (orders:write,
vault:write). A partner using this surface cannot place orders or
move funds with the same key.
- Privy JWT sessions are explicitly rejected on these endpoints — they
are partner-only.
The scope is selectable in the admin-panel API-key issuance form
(checkbox alongside markets:read, events:read, etc.).
Trades feed
Cross-wallet executed-trade feed. Cursor-paginated and incremental by
modification time.
GET /api/v1/partner/trades
X-Api-Key: ps_live_<keyId>_<secret>
Query parameters
| Parameter | Type | Required | Default | Description |
|---|
modifiedSince | ISO-8601 string | Yes | — | Returns trades whose max(createdAt, settledAt) is at or after this value. |
cursor | string | No | null | Opaque token from the previous response’s nextCursor. Pass back unchanged. |
limit | integer | No | 50 | Page size. Min 1, max 300. |
marketId | string | No | — | Restrict results to a single market symbol. |
Response — 200 OK
{
trades: PartnerTrade[];
nextCursor: string | null; // null when window fully drained
}
PartnerTrade:
{
tradeId: string; // upsert key
status: 'matched' | 'settlement_pending' | 'settled' | 'settlement_failed';
marketSymbol: string;
marketTitle: string | null;
eventId: string | null;
eventTitle: string | null;
categoryTags: string[]; // tag-id list
matchedAt: string; // ISO-8601, immutable
settledAt: string | null; // ISO-8601 once on-chain confirmed
txHash: string | null;
price: string; // decimal, USDC
quantity: string; // decimal, outcome-token units
takerFee: PartnerTradeFee;
makerFee: PartnerTradeFee; // always { amount: '0', currency: 'USDC', tokenId: null }
taker: PartnerTradeSide;
maker: PartnerTradeSide;
}
PartnerTradeFee:
{
amount: string; // decimal
currency: 'USDC' | 'OUTCOME_TOKENS';
tokenId: string | null; // non-null iff currency='OUTCOME_TOKENS'
}
PartnerTradeSide (identical shape on taker and maker):
{
side: 'BUY' | 'SELL';
walletAddress: string; // user EOA the order was signed from
vaultAddress: string; // smart-contract wallet that held collateral / outcome tokens
orderId: string;
orderType: 'LIMIT' | 'MARKET';
orderTimeInForce: string; // 'GTC' | 'IOC' | 'FOK' | 'GTD'
orderPlacedAt: string; // ISO-8601
orderOriginalQty: string;
orderRemainingQty: string; // remaining at the time of THIS trade
}
Example
GET /api/v1/partner/trades?modifiedSince=2026-05-01T00:00:00Z&limit=50
X-Api-Key: ps_live_<keyId>_<secret>
{
"trades": [
{
"tradeId": "1042",
"status": "settled",
"marketSymbol": "WC26-GROUP-A-ARG-MEX-1",
"marketTitle": "Will Argentina beat Mexico?",
"eventId": "evt_argmex_q1",
"eventTitle": "Argentina vs Mexico",
"categoryTags": ["world-cup", "group-stage"],
"matchedAt": "2026-05-01T12:34:56.123456Z",
"settledAt": "2026-05-01T12:35:12.789012Z",
"txHash": "0xabc...",
"price": "0.65",
"quantity": "100.0",
"takerFee": { "amount": "0.42", "currency": "USDC", "tokenId": null },
"makerFee": { "amount": "0", "currency": "USDC", "tokenId": null },
"taker": {
"side": "BUY",
"walletAddress": "0x014eab...",
"vaultAddress": "0x3ef9a2...",
"orderId": "ord_xyz",
"orderType": "LIMIT",
"orderTimeInForce": "GTC",
"orderPlacedAt": "2026-05-01T12:30:00.000000Z",
"orderOriginalQty": "100.0",
"orderRemainingQty": "0"
},
"maker": { /* same shape */ }
}
],
"nextCursor": "eyJ0cyI6IjIwMjYtMDUtMDFUMTI6MzQ6NTYuMTIzNDU2WiIsImlkIjoiMTA0MiJ9"
}
Behaviour notes
- Idempotency. A single trade may surface twice — once when matched
(
status='matched', settledAt: null), again when settlement lands
(status='settled', settledAt: <iso>). Partners are expected to
upsert by tradeId.
- In-walk re-emit. The same trade can re-emit within a single cursor
walk if its settlement lands between page N and N+1. Same upsert rule
applies.
modifiedSince must stay constant across all cursor pages of a
single drain.
- Settlement failures are emitted with
status='settlement_failed'
— partners must NOT filter these out client-side.
Status codes
| Code | When |
|---|
200 | Success (incl. empty trades: [] page) |
400 | Malformed query (see Errors) |
401 | Missing or invalid X-Api-Key |
403 | Authenticated but key lacks partner:trades:read, or JWT used instead of API-key |
429 | Rate limit exceeded |
5xx | Internal failure (transient — retry with exponential backoff) |
Rate limit
- Per API-key: 600 requests / minute (default; can be raised per
partner via
partner.rate_limit_per_min).
- Per IP: 1000 requests / minute (defence-in-depth on egress IP).
Reconciliation snapshot
Window-aggregate cross-check for a partner’s local copy of trades.
Returns counts, sums, and a deterministic content hash over the trade
ids in the window.
GET /api/v1/partner/reconciliation/snapshot
X-Api-Key: ps_live_<keyId>_<secret>
Query parameters
| Parameter | Type | Required | Description |
|---|
from | ISO-8601 string | Yes | Inclusive lower bound. Compared against max(createdAt, settledAt). |
to | ISO-8601 string | Yes | Exclusive upper bound. Window length capped at 24 hours. |
The from / to bounds use the same max(createdAt, settledAt)
expression as the trade feed’s modifiedSince. The window aligns 1:1
with trades the partner pulled via ?modifiedSince=.
Response — 200 OK
{
window: { from: string; to: string };
totals: {
tradeCount: number;
totalQuantity: string; // decimal, outcome-token units
totalUsdcVolume: string; // SUM(price * quantity), USDC
totalTakerFeesUsdc: string; // taker fees in USDC over window
totalTakerFeesOutcomeTokens: Array<{
tokenId: string;
amount: string;
}>; // taker fees by outcome token
};
fingerprint: {
algorithm: 'sha256-csv-trade-ids';
value: string; // 64-char lowercase hex
};
computedAt: string; // ISO-8601
}
Fingerprint algorithm
sha256 of the trade ids in the window, sorted lexicographically as
decimal strings and joined by commas:
import hashlib
ids = sorted(str(t.tradeId) for t in trades_in_window) # string sort
fp = hashlib.sha256(",".join(ids).encode()).hexdigest()
Sort as strings, not as integers. ["1", "10", "2"], not
["1", "2", "10"]. The server matches the default sort order in
Python / JavaScript / Go.
Empty-window canonical (no trades in [from, to)):
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
(SHA-256 of the empty string).
Stability
| Field | Stability |
|---|
tradeCount, totalQuantity, totalUsdcVolume, fingerprint | Stable for past windows (to <= now). Trade timestamps are not back-dated. |
totalTakerFeesUsdc, totalTakerFeesOutcomeTokens | May increase across calls in live windows that contain matched (in-flight) trades. The fee-ledger row is written at settlement time. Past windows in which every trade has reached a terminal state are stable. |
Status codes
| Code | When |
|---|
200 | Success |
400 | invalid_window (from ≥ to or missing) / window_too_large (>24h) |
401 | Missing or invalid X-Api-Key |
403 | Scope missing or JWT used instead of API-key |
429 | Rate limit exceeded |
5xx | Internal failure |
Rate limit
- Per API-key: 60 requests / minute (recon is meant for periodic
polling, not high-frequency).
- Per IP: 200 requests / minute.
Error envelope
All errors follow the project-standard JSON shape:
{
code: string;
message: string;
}
Codes used by these endpoints
| HTTP | code | Meaning |
|---|
| 400 | invalid_modified_since | modifiedSince not a valid ISO-8601 timestamp |
| 400 | invalid_cursor | Cursor is malformed / not produced by us |
| 400 | invalid_window | from ≥ to or either field missing |
| 400 | window_too_large | Reconciliation window > 24 hours |
| 401 | api_key_required | X-Api-Key header missing |
| 403 | api_key_required_not_jwt | Authenticated as JWT user; this surface is API-key-only |
| 403 | api_key_scope_missing | API key valid but lacks partner:trades:read scope |
| 429 | (no body code; see Retry-After header) | Rate limit exceeded |
| 5xx | internal_error | Transient — retry with exponential backoff |