JavaScript · TypeScriptv0.1.2MIT

The official JavaScript SDK for the odds API

One typed client for REST on 60+ bookmakers, the live WebSocket and delta streams. It paces every request under your plan's limits, retries what is safe to retry, walks every page for you and picks sockets up where they dropped.

Install
npm install @pulsescore/sdk
quickstart.ts
import { PulseScore } from "@pulsescore/sdk";

const ps = new PulseScore({ apiKey: process.env.PULSESCORE_API_KEY, plan: "pro" });

// Prematch soccer from one bookmaker, one page
const { events } = await ps.bookmaker("betfair-sb").events("soccer", { limit: 30 });

// Live soccer as a delta stream: the board once, then only what changed
const stream = ps.stream({
  streams: [{ bookmaker: "betfair-sb", kind: "live", sport: "soccer" }],
});
stream.on("update", (u) => console.log(u.stream, u.patched.length, "events changed"));

The parts you would otherwise write yourself

Every bookmaker, one client

ps.bookmaker(id) knows each bookmaker's paths, including bet365 under /api/v3 and the books whose race cards come whole, so every bookmaker is called the same way. bookmakers() lists what is online right now, with its sports, live socket and streams, and needs no key.

Rate limits, handled

Requests to each bookmaker are spaced under your plan's limit, learned from the X-RateLimit headers or set with the plan option, so the SDK avoids 429s instead of retrying through them. Bookmakers never wait for each other, and network errors and 502/503/504 are retried with backoff.

Pages as iterators

for await walks every page of events, leagues, live events, results and races at the largest page size the API allows, so a whole board costs as few requests as possible. An item that shifts to the next page while you read is not yielded twice.

Live WebSocket

One socket per sport delivers the whole live board on every frame. It reconnects through drops and our deploys with jittered backoff, waits out the server's cooldown on 4429 and stops for good on the codes a retry cannot fix, such as a bad key or a plan without sockets.

Delta streams

Each stream's board is built from its snapshot and every delta, checked against the stream server's own golden fixtures, so it matches what the REST API serves. After a drop it resumes from the exact sequence number, a 64-bit value JavaScript numbers cannot hold, with no new snapshot.

Typed, zero dependencies

TypeScript types for events, markets, selections, results and races, typed errors for every status, ES modules and CommonJS. No runtime dependencies, and about 35 KB minified in a browser bundle.

REST, the live socket and streams, one client

Sports are kebab-case (ice-hockey); the snake_case names the live and results lists return can be passed back unchanged. Every list and lookup has a typed result, and every failure is a typed error carrying the status and the response body, never your key.

REST: prematch, live, results
import { PulseScore } from "@pulsescore/sdk";

const ps = new PulseScore({ apiKey: process.env.PULSESCORE_API_KEY, plan: "pro" });
const betfair = ps.bookmaker("betfair-sb");

const { events } = await betfair.events("soccer", { limit: 30 });   // one page of prematch
const inPlay = await betfair.live.events({ sport: "tennis" });        // live, with score and clock
const event = await betfair.event("soccer", events[0].eventId);      // null for an unknown id

// Every page, at the largest page size the API allows
for await (const ev of betfair.iterateEvents("basketball")) {
  console.log(ev.home, ev.away, ev.markets?.length);
}

// Finished events, newest first
for await (const r of ps.bookmaker("netbet").results.iterate({ sport: "tennis", maxPages: 5 })) {
  console.log(r.home, r.away, r.score);
}
Live WebSocket (PRO and up)
const live = ps.bookmaker("betfair-sb").live.subscribe("soccer");

live.on("connected", (info) => console.log(info.plan, info.validSports));
live.on("data", (events) => render(events));            // the whole live board, every frame
live.on("state", (state, info) => console.log(state, info));

// later
await live.close();
Delta streams (PRO and up)
const stream = ps.stream({
  streams: [
    { bookmaker: "betfair-sb", kind: "live", sport: "soccer" },
    { bookmaker: "betfair-sb", kind: "prematch", sport: "tennis", markets: ["MATCH_RESULT"] },
    { bookmaker: "betfair-sb", kind: "racing", sport: "horse-racing" },
  ],
});

stream.on("update", (u) => {
  u.upserted;   // events added or replaced, as they are now
  u.patched;    // events that changed, as they are now
  u.removed;    // [{ id, reason }]
});

await stream.ready();                                   // every stream holds its board
const board = stream.events("betfair-sb/live/soccer");  // the whole board, as REST serves it

SDK questions

How do I install the PulseScore JavaScript SDK?

Run npm install @pulsescore/sdk, then create a client with new PulseScore({ apiKey }) or set the PULSESCORE_API_KEY environment variable. The package has no runtime dependencies and ships ES modules, CommonJS and TypeScript declarations.

Which plans can use the SDK?

The SDK is free and MIT-licensed, and it works with every PulseScore plan, including the free BASIC plan. REST calls to all 60+ bookmakers work on every plan; the live WebSocket and delta streams need PRO, MAX or ULTRA.

How does the SDK handle rate limits?

The API limits each key per bookmaker, and a key that collects ten 429 responses within ten seconds is paused for a minute. The SDK spaces requests to each bookmaker under your plan's limit, learned from the X-RateLimit headers or set with the plan option, so it avoids 429s instead of retrying through them. A plain 429 waits one window and is retried; a paused key or an exhausted monthly quota is thrown as a RateLimitError.

Which runtimes does it support?

Node.js 20 and newer for REST, and browsers. The WebSockets use the runtime's own WebSocket, which Node.js 22+, browsers, Deno and Bun provide; on Node.js 20 or 21, install the ws package and pass it as new PulseScore({ WebSocket }).

Can I use the SDK in the browser?

Yes: it bundles to about 35 KB minified with no Node.js built-ins. An API key in a web page is public, though, so prefer calling the API from your server. In the browser, set authMode: 'query' so the key travels as a query parameter and no CORS preflight is needed.

Is there a Python or Go SDK?

Not yet; JavaScript and TypeScript come first. The REST API, the live WebSocket and the delta-stream protocol are plain JSON over HTTPS and WebSocket, so any language can call them directly: the documentation has Python examples and a reference Python stream client.

Install it, add a key, call any bookmaker

The free BASIC plan is enough to try every bookmaker over REST. The documentation has the full contract behind every SDK call: the schema, the endpoints, the WebSocket frames and the error codes.