Skip to main content

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:
  1. GET /api/v1/partner/trades — incremental, cross-wallet trade feed.
  2. 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

ParameterTypeRequiredDefaultDescription
modifiedSinceISO-8601 stringYesReturns trades whose max(createdAt, settledAt) is at or after this value.
cursorstringNonullOpaque token from the previous response’s nextCursor. Pass back unchanged.
limitintegerNo50Page size. Min 1, max 300.
marketIdstringNoRestrict 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

CodeWhen
200Success (incl. empty trades: [] page)
400Malformed query (see Errors)
401Missing or invalid X-Api-Key
403Authenticated but key lacks partner:trades:read, or JWT used instead of API-key
429Rate limit exceeded
5xxInternal 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

ParameterTypeRequiredDescription
fromISO-8601 stringYesInclusive lower bound. Compared against max(createdAt, settledAt).
toISO-8601 stringYesExclusive 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

FieldStability
tradeCount, totalQuantity, totalUsdcVolume, fingerprintStable for past windows (to <= now). Trade timestamps are not back-dated.
totalTakerFeesUsdc, totalTakerFeesOutcomeTokensMay 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

CodeWhen
200Success
400invalid_window (from ≥ to or missing) / window_too_large (>24h)
401Missing or invalid X-Api-Key
403Scope missing or JWT used instead of API-key
429Rate limit exceeded
5xxInternal 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

HTTPcodeMeaning
400invalid_modified_sincemodifiedSince not a valid ISO-8601 timestamp
400invalid_cursorCursor is malformed / not produced by us
400invalid_windowfromto or either field missing
400window_too_largeReconciliation window > 24 hours
401api_key_requiredX-Api-Key header missing
403api_key_required_not_jwtAuthenticated as JWT user; this surface is API-key-only
403api_key_scope_missingAPI key valid but lacks partner:trades:read scope
429(no body code; see Retry-After header)Rate limit exceeded
5xxinternal_errorTransient — retry with exponential backoff