predimarkets
v0.2.0
Published
Official TypeScript client for the Predimarkets API — markets, bets, settlement and webhooks for prediction markets.
Maintainers
Readme
predimarkets
Official TypeScript client for the Predimarkets API — markets, bets, settlement and webhooks for prediction markets.
Zero runtime dependencies. Runs on Node 18+, Bun, Deno and Cloudflare Workers.
npm install predimarketsQuick start
import { Predimarkets } from 'predimarkets';
const client = new Predimarkets({ apiKey: process.env.PREDIMARKETS_API_KEY! });
const { markets } = await client.markets.list({ status: 'open' });
const market = markets[0];
// Price the bet before you place it.
const quote = await client.quotes.get({
marketId: market.id,
outcomeId: market.outcomes[0].id,
stake: 100,
});
// Place it.
const order = await client.orders.create({
marketId: market.id,
outcomeId: market.outcomes[0].id,
userId: 'your-user-123',
amount: 100,
});Your API key authenticates you as the partner; userId is your id for the end
user placing the bet. Keep the key server-side — it must never reach a browser.
Markets
await client.markets.list({ status: 'open', limit: 20 });
await client.markets.get('will-france-win-the-world-cup-2026'); // id or slug
await client.markets.priceHistory(market.id, { timeframe: '1D' });Search is semantic, not just keyword — queries are ranked by meaning, so a question finds the market that answers it even when they share no words:
await client.markets.search('who wants to be president');Bets
amount is the money the user is staking. That is all a market needs:
await client.orders.create({
marketId, outcomeId, userId: 'user-123', amount: 100,
});Quote first if you want to show the user what they stand to win:
const quote = await client.quotes.get({ marketId, outcomeId, stake: 100 });
// quote.multiplier — the return they lock in
// quote.estimated_payout — what they take home if it hitsPositions and trades
await client.positions.list({ userId: 'user-123' });
await client.trades.list({ userId: 'user-123', limit: 50 });Markets with more than two outcomes
Pass multiOutcome:
const state = await client.marketState.get(marketId, { multiOutcome: true });
const quote = await client.quotes.get({ marketId, outcomeId, stake: 50, multiOutcome: true });An outcome that is out of the running (knocked out, lost) comes back with
eliminated: true and takes no new bets — the API rejects them with
OUTCOME_ELIMINATED. Render it as dead rather than hiding it, so the remaining
outcomes' percentages still add up for the user.
Webhooks
Predimarkets signs every webhook with HMAC-SHA256 over the raw body, in the
x-predimarkets-signature header.
import { Predimarkets, SIGNATURE_HEADER } from 'predimarkets';
app.post('/webhooks/predimarkets', express.raw({ type: 'application/json' }), async (req, res) => {
const event = await client.webhooks.constructEvent({
payload: req.body.toString('utf8'), // the RAW bytes, not the parsed JSON
signature: req.headers[SIGNATURE_HEADER],
secret: process.env.PREDIMARKETS_WEBHOOK_SECRET!,
});
// constructEvent throws if the signature is wrong, so you cannot forget to check.
switch (event.event_type) {
case 'market.resolved': /* pay your users */ break;
case 'positions.refund': /* credit the refund */ break;
}
res.sendStatus(200);
});Pass the raw body. Re-serialising parsed JSON changes a byte somewhere (key order, whitespace) and the signature will not match. The comparison is constant time, so it does not leak the secret to anyone timing your responses.
Errors
Every non-2xx response throws a PredimarketsError. Branch on code, never on
the message:
import { PredimarketsError } from 'predimarkets';
try {
await client.orders.create({ /* … */ });
} catch (err) {
if (err instanceof PredimarketsError) {
if (err.code === 'INSUFFICIENT_BALANCE') return topUp();
if (err.code === 'OUTCOME_ELIMINATED') return refreshMarket();
console.error(err.code, err.message, err.failureReason);
}
throw err;
}Anything not wrapped yet
client.request() reaches any endpoint directly, with auth, timeouts and error
handling already applied:
await client.request('GET', `/markets/${marketId}/milestone-live`);License
MIT
