Skip to main content
Audience: developers. This is a hands-on, copy-paste guide. For eligibility, agreements, and the business setup, see ISVs / IBs and Partner Onboarding.
This guide walks you through your first authenticated order on Polymarket US. By the end you’ll have:
  1. Authenticated with the API as your Firm
  2. Listed available instruments
  3. Checked a balance
  4. Placed and cancelled a limit order
Prerequisites: Complete Partner Onboarding to receive your Client ID and register your public key. This guide uses pre-production (api.preprod.polymarketexchange.com).

Step 1: Authenticate

Authentication uses Private Key JWT — you sign a JWT with your private key and exchange it for a short-lived access token. The full mechanism, claims, and key rotation are covered in the Authentication guide; the complete, runnable token code is in the full script at the bottom of this page. Once you have a token, set your auth header and confirm your identity with GET /v1/whoami:
import requests

BASE_URL = "https://api.preprod.polymarketexchange.com"
headers = {
    "Authorization": f"Bearer {access_token}",  # from the auth guide
    "Content-Type": "application/json",
}

resp = requests.get(f"{BASE_URL}/v1/whoami", headers=headers)
resp.raise_for_status()
print(f"Authenticated as: {resp.json()}")
Expected response:
{
  "user": "firms/ISV-Participant-Acme/users/admin",
  "userDisplayName": "Your Company",
  "firm": "ISV-Participant-Acme",
  "firmDisplayName": "Acme Trading",
  "firmType": "FIRM_TYPE_PARTICIPANT"
}
Acting on behalf of a participant. This quickstart trades as your Firm. To place orders for a specific Retail Participant, add the x-participant-id header — see Authentication → Acting on behalf of a participant. The mechanics for funding participant accounts are coming soon.

Step 2: List available instruments

Find instruments to trade with the Reference Data API (POST /v1/refdata/instruments):
resp = requests.post(
    f"{BASE_URL}/v1/refdata/instruments",
    headers=headers,
    json={"tradable_filter": "TRADABLE_FILTER_TRADABLE", "page_size": 5},
)
resp.raise_for_status()

instruments = resp.json().get("instruments", [])
for inst in instruments:
    print(f"  {inst['symbol']}: {inst.get('description', 'N/A')}")
Cache each instrument’s price_scale — you need it to convert prices to integers when placing orders.

Step 3: Check a balance

Confirm available funds with the Positions API (POST /v1/positions/balance):
resp = requests.post(f"{BASE_URL}/v1/positions/balance", headers=headers, json={})
resp.raise_for_status()
print(f"Available balance: {resp.json()}")

Step 4: Place a limit order

Submit a buy order with the Trading API (POST /v1/trading/orders):
import uuid

symbol = "tec-nfl-sbw-2026-02-08-kc"  # e.g. Kansas City Chiefs to win Super Bowl 2026
price_scale = 1000  # from instrument metadata (Step 2)

order = {
    "clord_id": str(uuid.uuid4()),                    # your unique order ID
    "symbol": symbol,
    "side": "SIDE_BUY",
    "type": "ORDER_TYPE_LIMIT",
    "time_in_force": "TIME_IN_FORCE_GOOD_TILL_CANCEL",
    "order_qty": 10,
    "price": int(0.50 * price_scale),                 # $0.50 as integer
}

resp = requests.post(f"{BASE_URL}/v1/trading/orders", headers=headers, json=order)
if resp.status_code == 200:
    result = resp.json()
    print(f"Order placed: {result['order']['id']} ({result['order']['state']})")
else:
    print(f"Order failed: {resp.text}")
Expected response:
{
  "order": {
    "id": "ord_abc123",
    "clord_id": "your-uuid",
    "symbol": "tec-nfl-sbw-2026-02-08-kc",
    "side": "SIDE_BUY",
    "state": "ORDER_STATE_NEW",
    "order_qty": 10,
    "price": 5000,
    "leaves_qty": 10,
    "cum_qty": 0
  }
}
Streaming-first. To track order and fill updates in production, subscribe to the order stream rather than polling. REST search (below) is for one-off checks and backfill.

Step 5: Check your order

Look up open orders with the Report API (POST /v1/report/orders/search):
resp = requests.post(
    f"{BASE_URL}/v1/report/orders/search",
    headers=headers,
    json={"symbols": [symbol], "state_filter": "ORDER_STATE_FILTER_OPEN"},
)
resp.raise_for_status()

for order in resp.json().get("orders", []):
    print(f"  {order['id']}: {order['side']} {order['order_qty']} @ {order['price'] / price_scale:.2f}")

Step 6: Cancel your order

Cancel with the Trading API (POST /v1/trading/orders/cancel):
resp = requests.post(
    f"{BASE_URL}/v1/trading/orders/cancel",
    headers=headers,
    json={"order_id": "ord_abc123"},  # from Step 4
)
print("Order cancelled!" if resp.status_code == 200 else f"Cancel failed: {resp.text}")

Complete example

A single runnable script — including the full token exchange (see the Authentication guide for an explanation of each claim):
#!/usr/bin/env python3
"""Polymarket US partner quickstart — place your first order."""

import jwt
import uuid
import time
import requests
from cryptography.hazmat.primitives import serialization

# Configuration (from Partner Onboarding)
AUTH_DOMAIN = "pmx-preprod.us.auth0.com"
CLIENT_ID = "your_client_id"
AUDIENCE = "https://api.preprod.polymarketexchange.com"
PRIVATE_KEY_PATH = "private_key.pem"
BASE_URL = "https://api.preprod.polymarketexchange.com"


def get_access_token():
    with open(PRIVATE_KEY_PATH, "rb") as f:
        private_key = serialization.load_pem_private_key(f.read(), password=None)

    now = int(time.time())
    claims = {
        "iss": CLIENT_ID,
        "sub": CLIENT_ID,
        "aud": f"https://{AUTH_DOMAIN}/oauth/token",
        "iat": now,
        "exp": now + 300,
        "jti": str(uuid.uuid4()),
    }
    assertion = jwt.encode(claims, private_key, algorithm="RS256")

    response = requests.post(
        f"https://{AUTH_DOMAIN}/oauth/token",
        json={
            "client_id": CLIENT_ID,
            "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
            "client_assertion": assertion,
            "audience": AUDIENCE,
            "grant_type": "client_credentials",
        },
    )
    response.raise_for_status()
    return response.json()["access_token"]


def main():
    token = get_access_token()
    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

    # Verify identity
    resp = requests.get(f"{BASE_URL}/v1/whoami", headers=headers)
    resp.raise_for_status()
    print(f"Logged in as: {resp.json()}")

    # List instruments
    resp = requests.post(
        f"{BASE_URL}/v1/refdata/instruments",
        headers=headers,
        json={"tradable_filter": "TRADABLE_FILTER_TRADABLE", "page_size": 5},
    )
    resp.raise_for_status()
    instruments = resp.json().get("instruments", [])
    if not instruments:
        print("No instruments available. Exiting.")
        return

    symbol = instruments[0]["symbol"]
    price_scale = instruments[0].get("price_scale", 1000)
    print(f"Using: {symbol} (price_scale={price_scale})")

    # Place order
    order = {
        "clord_id": str(uuid.uuid4()),
        "symbol": symbol,
        "side": "SIDE_BUY",
        "type": "ORDER_TYPE_LIMIT",
        "time_in_force": "TIME_IN_FORCE_GOOD_TILL_CANCEL",
        "order_qty": 10,
        "price": int(0.50 * price_scale),
    }
    resp = requests.post(f"{BASE_URL}/v1/trading/orders", headers=headers, json=order)
    if resp.status_code != 200:
        print(f"Order failed: {resp.text}")
        return

    order_id = resp.json()["order"]["id"]
    print(f"Order placed: {order_id}")

    # Cancel order
    resp = requests.post(
        f"{BASE_URL}/v1/trading/orders/cancel",
        headers=headers,
        json={"order_id": order_id},
    )
    print("Order cancelled!" if resp.status_code == 200 else f"Cancel failed: {resp.text}")


if __name__ == "__main__":
    main()
Required packages:
pip install PyJWT cryptography requests

Next steps

Authentication

Token refresh, key rotation, and scopes.

Funding

How participant accounts are funded (coming soon).

gRPC Streaming

Real-time order, position, and market data.

Trading API

Full order-entry endpoint reference.