The Poly Syncer API is what the panel uses internally — same endpoints, same payload shapes, same rate limits. We ship the same API to developers because we’d rather you build on top of us than reverse-engineer us. Whether you are building a custom Polymarket bot on top of our signal feed, wiring the Polymarket leaderboard into a research notebook, or running automated Polymarket trading from your own infrastructure, the contract is identical. It is the same data layer that makes prediction market copy trading work end-to-end inside the panel. The surface is split into three families: /leaderboard for ranked wallet data, /signals for the live trade firehose, and /portfolio for your own book.
Base URL and versioning
Production base: https://api.polysyncer.com/v1. The /v1 prefix is permanent — we will ship a /v2 rather than break a contract. Deprecation notices land in the changelog at least 90 days before any field is removed, and the X-PolySyncer-Deprecation response header surfaces field-level deprecations on every call.
Authentication
API key (Pro)
Pro plans get a 64-byte API key, generated from the panel and rotated whenever you choose. Pass it as the Authorization: Bearer <key> header on every request. Keys are scoped read-only to the leaderboard, the public signal feed (10-second delayed), and your own portfolio. Keys can be ACL-restricted to a CIDR range, and every key issues a per-request audit log row that you can fetch via /audit.
Signed request (Elite)
Elite unlocks the full raw signal feed — the same sub-second push the Elite panel consumes. To prevent leakage, the raw feed is gated behind an EIP-712 signed request rather than a bearer key. Each call (or each WebSocket subscription) carries a signature over a typed message that includes a nonce and a timestamp; the server verifies the signer matches a wallet on your Elite plan and rejects anything older than 30 seconds. There is no key to leak because there is no key.
REST endpoints (selected)
| Method | Path | Purpose |
|---|---|---|
| GET | /leaderboard | Ranked wallets with composite score, Sharpe, ROI, drawdown. |
| GET | /leaderboard/:wallet | Full profile: equity curve, per-category breakdown, open positions. |
| GET | /strategies | Pre-built strategy templates and your active configs. |
| GET | /portfolio/positions | Open positions for the authenticated account. |
| GET | /portfolio/pnl?window=30d | Realized + unrealized PnL series. |
| POST | /portfolio/export | Generate a signed CSV/JSON export URL (24h TTL). |
WebSocket signal feed
Endpoint: wss://stream.polysyncer.com/v1/signals. After connect, send a subscribe frame naming the channels you want. Channels are: leaderboard.delta (rank changes), signals.public (10s-delayed trade signals, available to Pro), and signals.raw (sub-second raw feed, Elite only, signed-subscribe required).
TypeScript example — subscribe to the raw feed
// Elite — signed subscribe to the raw signal feed
import { WebSocket } from "ws";
import { signTypedData } from "./eip712";
const ws = new WebSocket("wss://stream.polysyncer.com/v1/signals");
ws.on("open", async () => {
const nonce = crypto.randomUUID();
const ts = Math.floor(Date.now() / 1000);
const sig = await signTypedData(walletPrivateKey, {
domain: { name: "Poly Syncer", version: "1", chainId: 137 },
types: { Subscribe: [
{ name: "channel", type: "string" },
{ name: "nonce", type: "string" },
{ name: "timestamp", type: "uint64" },
] },
primaryType: "Subscribe",
message: { channel: "signals.raw", nonce, timestamp: ts },
});
ws.send(JSON.stringify({
op: "subscribe",
channel: "signals.raw",
auth: { signer: walletAddress, signature: sig, nonce, timestamp: ts },
}));
});
ws.on("message", (raw) => {
const evt = JSON.parse(raw.toString());
if (evt.type === "trade") {
console.log(`${evt.wallet} ${evt.side} ${evt.shares} @ ${evt.prob} on ${evt.market}`);
}
});
TypeScript example — fetch the leaderboard (Pro)
const res = await fetch("https://api.polysyncer.com/v1/leaderboard?limit=50&sort=sharpe", {
headers: { Authorization: `Bearer ${process.env.POLYSYNCER_KEY}` },
});
const { wallets } = await res.json();
for (const w of wallets) {
console.log(w.rank, w.address, w.sharpe.toFixed(2), w.roi30d, w.drawdown);
}
Rate limits
| Plan | REST | WebSocket subscriptions | Signal feed |
|---|---|---|---|
| Pro | 60 req/min | 3 concurrent | Public, 10s delayed |
| Elite | 600 req/min | 25 concurrent | Raw, sub-second, signed |
Limits are enforced as a token bucket with a 10-second refill, so a short burst above the per-minute average is tolerated. Rate-limit state is exposed on every response via X-RateLimit-Remaining and X-RateLimit-Reset. Sustained 429s after retry-after backoff indicate your client is mis-paginating — see the developer docs for cursor patterns.
Errors and idempotency
Errors return RFC 7807 problem documents with stable type URIs. Mutating endpoints accept an Idempotency-Key header and dedupe on it for 24 hours. WebSocket disconnects are surfaced with a typed close frame; reconnection should be exponential-backoff with jitter, capped at 30 seconds.
SLAs and status
The Elite raw feed is engineered for sub-second p99 from on-chain confirmation to subscriber receipt. The REST surface targets 99.9% monthly availability. Live operational status, regional latency, and incident history are published on the status page; security and threat-model details are on the security page.