Skip to main content

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 itself is read-only, but it is not exclusive: a key can carry partner:trades:read together with write scopes such as orders:write or vault:write. If you want an audit-only credential, ask for a key that holds partner:trades:read alone, and store any key that also holds a write scope as a trading credential.
  • Web-app user session tokens (Authorization: Bearer) are explicitly rejected on these endpoints — they are partner-only.
  • A multi_wallet key must still send X-User-Wallet on these requests, as on every request (see API keys); the feed itself is not filtered by that wallet.
Keys with this scope are issued by PredictStreet: ask your integration manager to add partner:trades:read to your key.

Trades feed

Cross-wallet executed-trade feed. Cursor-paginated and incremental by modification time.

Query parameters

Response — 200 OK

PartnerTrade:
PartnerTradeFee:
Both legs of a fill are charged, and each fee field carries the fee that leg paid. The fee take for one fill is takerFee + makerFee, so do not read takerFee as the trade total. A BUY leg is charged in OUTCOME_TOKENS and a SELL leg in USDC, so the two legs of one fill are often in different currencies: sum them per currency, and don’t convert OUTCOME_TOKENS to USDC without applying the trade price. A leg reads { amount: '0', currency: 'USDC', tokenId: null } only when it has no fee row: a settlement_failed trade (it never settled, so no fee was taken on either leg, even if an earlier pull showed one), trades from before 28 April 2026, or an in-flight trade whose row has not been written yet (that one shows its fee on a later pull). PartnerTradeSide (identical shape on taker and maker):
maker.side is always reported as the opposite of taker.side. On a binary-market fill where both parties bought (one YES, one NO) or both sold, the maker actually traded the same side as the taker.

Example

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 included with status='settlement_failed' — do NOT filter them out client-side. A failure does not always move modifiedAt, so a trade you stored as matched or settlement_pending can fail without showing up again on your incremental pull. Periodically re-pull a trailing window (for example modifiedSince = now − 24 h) and upsert, so rows that were not yet final pick up their final status.

Status codes

Rate limit

  • Per partner (one bucket shared by all of your API keys): 600 requests / minute by default. The limit scales with your account’s rate tier, which PredictStreet can raise.
  • 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.

Query parameters

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

The fee take over the window is the taker totals plus the maker totals, summed per currency.

Fingerprint algorithm

sha256 of the trade ids in the window, sorted lexicographically as decimal strings and joined by commas:
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

Snapshots of past windows are cached for up to 1 hour, live windows for 60 seconds.

Status codes

Rate limit

  • Per partner (shared by all of your API keys): 60 requests / minute by default, scaled by the same account rate tier (recon is meant for periodic polling, not high-frequency).
  • Per IP: 200 requests / minute.

Error envelope

All errors use the platform error envelope:

Codes used by these endpoints