SDKs and the copy-trading bot
Official open-source (MIT) clients for Node.js and Python, and a ready-to-run Polymarket copy-trading bot built on them.
The SDKs wrap every endpoint in the API documentation and handle the WebSocket for you: reconnect and keep-alive, missed frames detected by session/seq and replayed from the last fill delivered, de-duplication by eventId, and a persisted cursor so a restart resumes where it stopped. Delivery is at least once: the cursor is saved after your handler returns, so a crash in between replays that fill on restart — make your handler idempotent on eventId. You need an API key — create one on the keys page.
Node.js SDK
pmwallets-node on GitHub, pmwallets on npm. Node.js ≥ 20, TypeScript types included.
npm install pmwallets
import { PmwClient, FillStream, FileStateStore, verifyWebhook } from 'pmwallets'; const pmw = new PmwClient({ apiKey: process.env.PMW_API_KEY! }); // who is making money on Polymarket, and how const board = await pmw.leaderboard({ minWinLo: 0.55, minEligible: 30, style: 'taker', status: 'active', limit: 50 }); // follow one (billed per entity per hour; 402 = balance too low, 409 = dormant) await pmw.subscribe({ entityId: board.rows[0].entityId, channels: ['ws'] }); // every fill of every entity you follow const stream = new FillStream({ client: pmw, store: new FileStateStore('./stream.json'), // a restart resumes from the last saved cursor onFill: async (fill, { source }) => console.log(source, fill.side, fill.price, fill.tokenId), onEvent: (e) => e.type === 'replaced' && console.warn('another connection took the stream'), }); await stream.start();
| What it does | |
|---|---|
PmwClient | leaderboard, entities, address unlocks, subscriptions, fills replay (fills, fillsSince), trade-history exports |
FillStream | WebSocket with reconnect and keep-alive; gap detection and replay; de-duplication; persisted cursor |
verifyWebhook(rawBody, signature, secret) | checks x-pmw-signature (HMAC-SHA256 of the raw body) |
Python SDK
pmwallets-python on GitHub, pmwallets on PyPI. Python ≥ 3.10, sync and asyncio clients.
pip install pmwallets
import asyncio from pmwallets import AsyncClient, Client, FillStream, FileStateStore # synchronous REST with Client(api_key="pmw_...") as pmw: board = pmw.leaderboard(minWinLo=0.55, minEligible=30, style="taker", status="active", limit=50) pmw.subscribe(board["rows"][0]["entityId"], channels=["ws"]) # billed per entity per hour # every fill of every entity you follow async def main(): async with AsyncClient(api_key="pmw_...") as pmw: stream = FillStream( client=pmw, store=FileStateStore("stream.json"), # a restart resumes from the last saved cursor on_fill=lambda fill, meta: print(meta.source, fill["side"], fill["price"], fill["tokenId"]), ) await stream.run() asyncio.run(main())
| What it does | |
|---|---|
Client / AsyncClient | leaderboard, entities, address unlocks, subscriptions, fills replay (fills, fills_since), trade-history exports |
FillStream | asyncio WebSocket with reconnect and keep-alive; gap detection and replay; de-duplication; persisted cursor |
verify_webhook(raw_body, signature, secret) | checks x-pmw-signature (HMAC-SHA256 of the raw body) |
Polymarket copy-trading bot
Built on the SDKs. You pick the traders on the board and subscribe; the bot receives each of their fills over the WebSocket and mirrors it on the Polymarket CLOB with your own account, inside the limits you set. Your keys never leave your machine — PMWallets never sees them and never places orders. It starts in dry-run: every decision is logged, nothing is traded.
Node.js
polymarket-copy-trading-bot · pmwallets-copytrade on npm
# Node.js ≥ 20 npm install -g pmwallets-copytrade pmwallets-copytrade init # writes config.yaml export PMW_API_KEY=pmw_... # https://pmwallets.com/keys pmwallets-copytrade run # dry-run: logs every decision, trades nothing
Python
polymarket-copy-trading-bot-python · pmwallets-copytrade on PyPI
# Python ≥ 3.10 pip install pmwallets-copytrade pmwallets-copytrade init # writes config.yaml export PMW_API_KEY=pmw_... # https://pmwallets.com/keys pmwallets-copytrade run # dry-run: logs every decision, trades nothing
Going live
When the dry-run log looks right, switch mode in config.yaml; the repository README covers setting up the Polymarket account.
mode: live polymarket: privateKey: ${POLY_PRIVATE_KEY} # signs your orders signatureType: 3 funderAddress: ${POLY_FUNDER_ADDRESS} # your Polymarket profile address (holds the USDC)
Which traders are worth following and how the bot decides: the copy-trading guide.
Where to run it
One stream per account: an API-key connection takes priority over the pmwallets.com feed page, and between two API connections the newest wins — so run one consumer per account. PMWallets’ servers are in the United Kingdom; for a trader who is eligible to use Polymarket’s API, a consumer that also places orders should run from Ireland (AWS eu-west-1), because Polymarket’s API does not accept orders from the UK, the US and several EU countries. The server’s region is not a way around your own eligibility.
API documentation · Measured push latency · Questions we get asked