Polymarket Bot Setup: Server, Keys, and First Order

Our Polymarket hosting guide covers where to run a prediction-market bot. This one covers how to stand the box up: provisioning, hardening, the client library, credential handling, and the supervision setup that decides whether your bot survives its first month. The strategy is yours. Everything below is the plumbing around it.
Polymarket's API surface changes faster than any blog post. Treat the commands here as the shape of the work, and check the current Polymarket developer docs for exact host names, client versions, and signature types before you go live.
Before you start
- A server. A small VPS is enough for a single-market loop. See the hosting guide for the region logic, and use our latency checker to measure round-trip time to the Polymarket endpoints from each candidate location before you commit.
- A funded wallet on Polygon. Polymarket settles in USDC on Polygon. Use a wallet dedicated to the bot, not your personal one.
- A little POL for gas. Approvals and on-chain actions cost gas even though order placement itself is off-chain.
- A local dry run. Get the client talking to the API from your laptop first. Debugging authentication over SSH on a fresh box is a bad first experience.
Step 1: provision the server
Deploy a Linux image you actually know. Ubuntu LTS is the safe default: the client libraries, Python builds, and systemd examples all assume it. On OrbitServers VPS the box is live within seconds of payment, which means the interesting work starts immediately.
Size it for the number of markets you intend to quote, not for the sophistication of the strategy. Two vCPUs and 4GB of RAM comfortably run a handful of subscriptions and an order loop. Scale the plan when headroom, not ambition, runs out.
Step 2: harden the box before the bot touches it
A trading bot holds a key that can spend money. The server it runs on deserves ten minutes of attention on day one:
adduser trader && usermod -aG sudo trader
# copy your public key up, then disable password auth
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
systemctl restart ssh
ufw default deny incoming && ufw default allow outgoing
ufw allow OpenSSH && ufw enable
apt update && apt install -y unattended-upgrades fail2ban
Nothing here is exotic. Key-only SSH, no root login, a default-deny firewall, automatic security updates. The bot needs no inbound ports at all: it makes outbound REST and WebSocket connections, so leaving only SSH open is correct.
Step 3: install a CLOB client
Polymarket publishes official clients for its central limit order book. Python is the common choice for bots:
apt install -y python3-venv
python3 -m venv ~/bot/.venv
source ~/bot/.venv/bin/activate
pip install py-clob-client
There is a TypeScript client as well if your stack is Node. Either way, pin the version in a requirements file or lockfile. An API client that silently upgrades under a running strategy is a self-inflicted incident.
Step 4: credentials, allowances, and key hygiene
Polymarket authentication has two layers. The first is your wallet key, which signs orders. The second is a set of API credentials derived from that key, which authenticate your requests to the order book. The client library derives the second from the first, so you provide the private key once, at startup, from the environment:
# ~/bot/.env (chmod 600, owned by the bot user, never in git)
POLY_PRIVATE_KEY=0x...
POLY_HOST=https://clob.polymarket.com
POLY_CHAIN_ID=137
Three rules make key handling boring, which is the goal:
- Never commit it. Environment file or secret store,
chmod 600, owned by the account that runs the bot. - Fund it thinly. Keep the trading wallet stocked with what the strategy needs for a few days, not with the treasury.
- Separate the roles. One wallet for the bot, one for holding. If the box is ever compromised, the blast radius should be a rounding error.
Before the first order, the exchange contracts need token allowances so they can move your USDC and outcome tokens. This is a one-time on-chain step per wallet, and it is the single most common reason a first order fails with an unhelpful error. If your wallet is a proxy or smart-contract wallet rather than a plain EOA, the client also needs the matching signature type. Both are documented in the Polymarket developer docs and both are worth confirming while you still have a terminal open and no live position.
Step 5: place one small order
Resist the urge to launch the strategy. Place a single tiny limit order well away from the mid price, confirm it appears, then cancel it. That one round trip proves the whole chain: credentials, allowances, signature type, network path, and clock. Every one of those fails differently, and finding out which one is broken while a quoting loop hammers the API is miserable.
Then read the market data path with the same skepticism: subscribe to the WebSocket feed for your market, print the first few updates, and check the sequencing looks sane before any logic consumes it.
Step 6: run it under systemd
A bot started inside an SSH session dies when the session does. A bot under systemd restarts on crash, starts on boot, and logs where you can find it:
[Unit]
Description=Polymarket bot
After=network-online.target
Wants=network-online.target
[Service]
User=trader
WorkingDirectory=/home/trader/bot
EnvironmentFile=/home/trader/bot/.env
ExecStart=/home/trader/bot/.venv/bin/python -u main.py
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Enable it with systemctl enable --now polymarket-bot and read the logs with journalctl -u polymarket-bot -f. Restart=always with a backoff covers the ordinary failure: a dropped WebSocket, a transient API error, an unhandled exception at 4am.
Restarting is not the same as recovering. On every start the bot should reconcile before it quotes: fetch open orders over REST, compare them with what it believes it has, cancel anything orphaned, and only then resume. A restart loop that re-quotes on top of stale orders is worse than an outage.
Step 7: monitoring that catches the quiet failures
Process death is the easy failure to detect. The expensive one is a bot that stays connected and trades on stale data. Alert on:
- Market data age. If the last book update is older than a few seconds during active hours, stop quoting and reconnect.
- Heartbeat gaps. Have the loop emit a timestamp every cycle, and alert when it stops moving.
- Order rejection rate. A sudden run of rejections usually means credentials, allowances, or rate limits, not strategy.
- Clock drift. Keep NTP running. Signature timestamps and rate-limit windows both punish a drifting clock.
- Disk and log growth. Set up log rotation on day one. Bots are verbose and disks are finite.
Step 8: know when to leave the VPS
A VPS is the right starting point and stays right for longer than most people expect. Move to bare metal when you quote many markets and scheduling jitter starts to show in fill quality, when you want hardware isolation for key custody, or when the Polymarket bot is one of several systems that should share a network. That last case is common: teams running Solana strategies alongside prediction-market bots consolidate onto a Frankfurt bare metal server or a New York box and keep everything on one fast, private network. The trading bot hosting page maps the full ladder.
Deployment checklist
- Region chosen by measurement, not by assumption
- SSH keys only, root login disabled, firewall default-deny
- Client library version pinned
- Private key in a
600environment file, dedicated wallet, thin balance - Allowances approved and one test order placed and cancelled
- systemd unit with restart, and reconciliation on startup
- Alerts on data age, heartbeat, and rejection rate
- Log rotation and NTP active
None of this is glamorous, and all of it is what separates a bot that runs for a weekend from one that runs for a year. When the plumbing is boring, the only variable left is the strategy, which is exactly where you want your attention.
Q&A
Question: Do I need a dedicated server to run a Polymarket bot?
Short answer: No. A small VPS with two vCPUs and 4GB of RAM runs a single-market loop comfortably, because the workload is I/O-bound rather than CPU-bound. Dedicated hardware becomes worthwhile when you quote many markets at once, want hardware isolation for key custody, or are consolidating several trading systems onto one network.
Question: Why did my first Polymarket order fail?
Short answer: In most first-run cases it is one of three things: token allowances were never approved for the exchange contracts, the client is configured with the wrong signature type for the wallet you are using, or the API credentials were not derived from the same key that signs the orders. Place one tiny order manually and cancel it before running any strategy, so you find out which.
Question: Should the bot restart automatically after a crash?
Short answer: Yes, but only if it reconciles on startup. Use systemd with Restart=always and a short backoff, then have the bot fetch its open orders over REST, cancel anything orphaned, and rebuild state before quoting again. Automatic restart without reconciliation stacks stale orders on top of new ones.
Question: Where should the private key live on the server?
Short answer: In an environment file readable only by the bot's own user account, loaded by systemd via EnvironmentFile, and never in the repository or a container image. Use a wallet dedicated to the bot and keep only the working balance in it, so a compromised box costs you a small balance rather than a portfolio.
Get started with Orbit Servers
Low-latency VPS, bare metal, and colocation across the US, EU, and APAC - provisioned instantly and built for performance-critical workloads.
Get startedRelated products
Written by
Ory
The Orbit Servers Team
The Orbit Servers team builds and operates low-latency VPS, bare metal, and colocation infrastructure across the US, EU, and APAC - with a focus on Solana RPC, validator, and trading workloads.