Skip to main content
Self-hosted PMXT runs the open-source pmxt-core server on your machine. The SDK detects the absence of a pmxt_api_key and routes through http://localhost:3847 instead of trade.pmxt.dev. Venue credentials stay on your machine; you talk to venue APIs directly.

When self-hosted is the right call

Pick self-hosted if any of these apply:
  • Sub-100ms latency — local submission removes a network hop. Matters for latency-sensitive arb / market-making.
  • Raw venue credentials — Polymarket L2 API keys, Kalshi RSA, Smarkets session cookies. Hosted mode doesn’t accept these.
  • Regulatory custody — you must be the direct counterparty with no intermediary in the custody path.
  • Venues hosted mode can’t write to yet — hosted writes are Polymarket, Opinion, and Limitless. Self-hosted can use venue-native credentials where the venue exposes writes (Kalshi, Smarkets, Probable, Myriad, Metaculus, etc.); check Feature Support & Compliance for per-venue support.
  • OSS contribution — you’re hacking on pmxt-core itself.

When hosted is still the better choice

Everyone else. Hosted is simpler to deploy (no local process), gives you on-chain custody you control via the timelock, and PMXT’s server never sees a private key. If you’re building a consumer app, a research notebook, or any non-latency-critical service against Polymarket, Opinion, or Limitless, stop here and use hosted.

1. Install pmxt-core

The SDK installs and supervises pmxt-core for you. You don’t run a separate binary; the SDK spawns it as a child process on first use.
pip install pmxt
npm install pmxtjs
That’s it — pmxt-core is bundled.

2. Construct without an API key

Drop the pmxt_api_key argument. The SDK detects the absence and starts the local server.
import pmxt

# No pmxt_api_key → SDK spawns and supervises pmxt-core locally
poly = pmxt.Polymarket()

markets = poly.fetch_markets(query="election", limit=3)
import { Polymarket } from "pmxtjs";

// No pmxtApiKey → SDK spawns and supervises pmxt-core locally
const poly = new Polymarket({});

const markets = await poly.fetchMarkets({ query: "election", limit: 3 });
The first call blocks briefly while the local server warms up; subsequent calls reuse the process.

3. Manage the local server

For lifecycle control (start, stop, restart, status, logs), use the server namespace. See Server Management for the full reference.
import pmxt

pmxt.server.start()       # idempotent
pmxt.server.health()      # bool
pmxt.server.status()      # structured snapshot
pmxt.server.stop()
pmxt.server.restart()
pmxt.server.logs(20)
Most users never call these — creating an exchange instance auto-starts the server.

4. Per-venue raw credentials

Self-hosted unlocks the full venue-credential surface. Pass credentials directly to the exchange constructor.

Polymarket — EVM private key

import pmxt

poly = pmxt.Polymarket(private_key="0xYourPrivateKey...")

order = poly.create_order(
    outcome=market.yes,
    side="buy",
    order_type="limit",
    price=0.42,
    amount=100,
)

Kalshi — RSA key pair

import pmxt

kalshi = pmxt.Kalshi(
    api_key_id="...",
    private_key_pem="-----BEGIN RSA PRIVATE KEY-----\n...",
)

Limitless / Probable / Opinion (self-hosted) — EVM private key

import pmxt

limitless = pmxt.Limitless(private_key="0x...")
probable  = pmxt.Probable(private_key="0x...")
opinion   = pmxt.Opinion(private_key="0x...")

Smarkets — email + password

import pmxt

smarkets = pmxt.Smarkets(email="you@example.com", password="...")

Baozi — Solana keypair

import pmxt

baozi = pmxt.Baozi(private_key="<base58 secret key>")
See Supported Venues for the full credential matrix.
For venues that use a fund-controlling private key (Polymarket, Limitless, Probable, Opinion, Baozi), a practical habit is to keep only the float you’re actively trading in this wallet.

5. Environment overrides

VariableEffect
PMXT_LOCAL_PORT=3847Override the local server port (default 3847).
PMXT_ALWAYS_RESTART=1Force-restart the local server on every ensure_server_running call. Useful during development.
PMXT_BASE_URLPoint the SDK at a custom server URL (advanced — defaults to http://localhost:3847).
See API Reference / Configuration for the full env-var matrix.

6. Running multiple exchanges

A single pmxt-core process can serve every venue. Construct multiple exchange clients against the same server — they all share the local process.
import pmxt

poly = pmxt.Polymarket(private_key="0x...")
kalshi = pmxt.Kalshi(api_key_id="...", private_key_pem="...")
# Both clients reuse the same pmxt-core process at http://localhost:3847

7. Production deployment

For production self-hosted, the SDK + bundled server is sufficient — there’s no separate daemon to manage. If you want to run pmxt-core as a long-lived process with systemd or similar, see the pmxt-core README for standalone server commands.

What you give up vs hosted

  • Cross-venue search via Router — still works, but requires the hosted pmxt_api_key for the catalog. If you want Router without trading-hosted, construct a separate Router client with the API key alongside your local trading clients. See Hosted trading.
  • Hosted error tree — you’ll get the parent classes (InvalidOrder, InsufficientFunds) but not the hosted leaves. Catching parents keeps your code portable.
  • PreFundedEscrow custody — irrelevant in self-hosted; you custody at the venue.

Next