A typed, dependency-free TypeScript client for the public Polymarket Gamma API.
The Gamma API is useful but awkward to consume directly: array fields like outcomes and outcomePrices arrive as JSON-encoded strings, and numbers come as strings inconsistently. This SDK normalizes all of that into real types, and adds pagination and retries.
- 🧯 Normalized data —
outcomes,outcomePrices,clobTokenIdsbecome real arrays; numeric strings become numbers. - 📦 Zero runtime dependencies — uses the built-in
fetch. - 🔁 Retries with backoff on
429/5xx/network errors. - 📄 Auto-pagination via an async iterator.
- 🧪 Fully typed and unit-tested (pure logic + mocked client).
- 🧩 Injectable
fetch— trivial to test or run behind a proxy.
npm install polymarket-gamma-sdkRequires Node.js ≥ 20 (or any runtime with global fetch).
import { GammaClient } from "polymarket-gamma-sdk";
const client = new GammaClient();
// Top markets by 24h volume
const markets = await client.getMarkets({
active: true,
closed: false,
limit: 5,
order: "volume24hr",
ascending: false,
});
for (const m of markets) {
console.log(m.question);
console.log(m.outcomes); // ["Yes", "No"] (already an array)
console.log(m.outcomePrices); // [0.52, 0.48] (already numbers)
console.log(m.liquidity, m.volume24hr);
}const market = await client.getMarketById(540817);
const event = await client.getEventById(16183);
console.log(event.title, event.markets.length, event.tags.map((t) => t.label));iterateMarkets walks the entire result set, managing limit/offset for you. Control the request size with pageSize (default 100):
let count = 0;
for await (const m of client.iterateMarkets({ active: true, closed: false }, { pageSize: 100 })) {
count++;
}
console.log(`scanned ${count} active markets`);const client = new GammaClient({
baseUrl: "https://gamma-api.polymarket.com", // override if needed
maxRetries: 3, // retries on 429/5xx/network
baseDelayMs: 300, // backoff base; doubles each attempt
fetch: myFetch, // inject a custom fetch (tests/proxies)
});Failed requests throw a GammaApiError carrying the HTTP status (or 0 for network errors) and the url:
import { GammaApiError } from "polymarket-gamma-sdk";
try {
await client.getMarketById(-1);
} catch (err) {
if (err instanceof GammaApiError) console.error(err.status, err.url);
}| Method | Returns |
|---|---|
getMarkets(query?) |
Promise<Market[]> |
getMarketById(id) |
Promise<Market> |
getEvents(query?) |
Promise<PolyEvent[]> |
getEventById(id) |
Promise<PolyEvent> |
iterateMarkets(query?, { pageSize?, signal? }) |
AsyncGenerator<Market> |
Also exported: buildQuery, normalizeMarket, normalizeEvent, normalizeTag, toNumber, toArray, and all types.
npm install
npm test # vitest
npm run typecheck
npm run buildUnofficial. Not affiliated with Polymarket. Read-only public data only.
MIT © blessedunit