Skip to main content
This guide will walk you through the complete lifecycle of placing and managing orders on Kalshi.

Prerequisites

Before you begin, you’ll need:
  • A Kalshi account with API access configured
  • Python with the requests and cryptography libraries installed
  • Your authentication functions set up (see our authentication guide)
This guide assumes you have the authentication code from our authentication guide, including the get() function for making authenticated requests.

Step 1: Find an Open Market

First, let’s find an open market to trade on.
# Get the first open market (no auth required for public market data)
response = requests.get('https://external-api.demo.kalshi.co/trade-api/v2/markets?limit=1&status=open')
market = response.json()['markets'][0]

print(f"Selected market: {market['ticker']}")
print(f"Title: {market['title']}")

Step 2: Place a Buy Order

Now let’s place an order to buy 1 YES contract for 1 cent (limit order). We’ll use a client_order_id to deduplicate orders - this allows you to identify duplicate orders before receiving the server-generated order_id in the response.
import uuid
from urllib.parse import urlparse

def post(private_key, api_key_id, path, data, base_url=BASE_URL):
    """Make an authenticated POST request to the Kalshi API."""
    timestamp = str(int(datetime.datetime.now().timestamp() * 1000))
    # Signing requires the full URL path from root (e.g. /trade-api/v2/portfolio/events/orders)
    sign_path = urlparse(base_url + path).path
    signature = create_signature(private_key, timestamp, "POST", sign_path)

    headers = {
        'KALSHI-ACCESS-KEY': api_key_id,
        'KALSHI-ACCESS-SIGNATURE': signature,
        'KALSHI-ACCESS-TIMESTAMP': timestamp,
        'Content-Type': 'application/json'
    }

    return requests.post(base_url + path, headers=headers, json=data)

# Place a buy order for 1 YES contract at 1 cent
order_data = {
    "ticker": market['ticker'],
    "side": "bid",
    "count": "1",
    "price": "0.0100",
    "time_in_force": "good_till_canceled",
    "self_trade_prevention_type": "taker_at_cross",
    "client_order_id": str(uuid.uuid4())  # Unique ID for deduplication
}

response = post(private_key, API_KEY_ID, '/portfolio/events/orders', order_data)

if response.status_code == 201:
    order = response.json()
    print(f"Order placed successfully!")
    print(f"Order ID: {order['order_id']}")
    print(f"Client Order ID: {order_data['client_order_id']}")
    print(f"Remaining Count: {order['remaining_count']}")
else:
    print(f"Error: {response.status_code} - {response.text}")

Complete Example Script

Here’s a complete script that creates your first order:
import requests
import uuid
from urllib.parse import urlparse
# Assumes you have the authentication code from the prerequisites

# Add POST function to your existing auth code
def post(private_key, api_key_id, path, data, base_url=BASE_URL):
    """Make an authenticated POST request to the Kalshi API."""
    timestamp = str(int(datetime.datetime.now().timestamp() * 1000))
    # Signing requires the full URL path from root (e.g. /trade-api/v2/portfolio/events/orders)
    sign_path = urlparse(base_url + path).path
    signature = create_signature(private_key, timestamp, "POST", sign_path)

    headers = {
        'KALSHI-ACCESS-KEY': api_key_id,
        'KALSHI-ACCESS-SIGNATURE': signature,
        'KALSHI-ACCESS-TIMESTAMP': timestamp,
        'Content-Type': 'application/json'
    }

    return requests.post(base_url + path, headers=headers, json=data)

# Step 1: Find an open market
print("Finding an open market...")
response = requests.get('https://external-api.demo.kalshi.co/trade-api/v2/markets?limit=1&status=open')
market = response.json()['markets'][0]
print(f"Selected: {market['ticker']} - {market['title']}")

# Step 2: Place a buy order
print("\nPlacing order...")
client_order_id = str(uuid.uuid4())
order_data = {
    "ticker": market['ticker'],
    "side": "bid",
    "count": "1",
    "price": "0.0100",
    "time_in_force": "good_till_canceled",
    "self_trade_prevention_type": "taker_at_cross",
    "client_order_id": client_order_id
}

response = post(private_key, API_KEY_ID, '/portfolio/events/orders', order_data)

if response.status_code == 201:
    order = response.json()
    print(f"Order placed successfully!")
    print(f"Order ID: {order['order_id']}")
    print(f"Client Order ID: {client_order_id}")
    print(f"Remaining Count: {order['remaining_count']}")
else:
    print(f"Error: {response.status_code} - {response.text}")

Important Notes

Client Order ID

The client_order_id field is optional, but strongly recommended for order deduplication:
  • Generate a unique ID (like UUID4) for each order before submission when you want idempotent retries
  • If network issues occur, you can resubmit with the same client_order_id
  • The API will reject duplicate submissions with the same client_order_id, preventing accidental double orders
  • Store this ID locally to track orders before receiving the server’s order_id

Error Handling

Common errors and how to handle them:
  • 401 Unauthorized: Check your API keys and signature generation
  • 400 Bad Request: Verify your order parameters (price must be 1-99 cents)
  • 409 Conflict: Order with this client_order_id already exists
  • 429 Too Many Requests: You’ve hit the rate limit - slow down your requests

Next Steps

Now that you’ve created your first order, you can:
  • Store the returned order_id and client_order_id for local tracking
  • Amend your order price or quantity using POST /portfolio/events/orders/{order_id}/amend
  • Cancel orders using DELETE /portfolio/events/orders/{order_id}
  • Implement WebSocket connections for real-time updates
  • Build automated trading strategies
For more information, check out: