🚧 Beta — AfterTrade is in early development. It's free during beta.Privacy Policy |Terms of Service

Kalshi API Integration Guide

How to authenticate with Kalshi's trading API using RSA-PSS signatures

1. The Authentication Problem

Most trading APIs use OAuth2 or JWT tokens. Kalshi doesn't. Their API uses RSA-PSS digital signatures to authenticate every single request.

This means:

  • There's no "login" endpoint that returns a token
  • You must cryptographically sign each request individually
  • The signature proves you possess the private key
  • Standard HTTP libraries won't work out of the box

2. How Kalshi Authentication Works

For each API request, you need to:

  1. Create a message to sign:
    timestamp + method + path

    Example: 1704398400000GET/trade-api/v2/portfolio/fills

  2. Sign the message using your private key with RSA-PSS (SHA-256)
  3. Base64-encode the signature
  4. Add three headers to your HTTP request:
    • KALSHI-ACCESS-KEY: Your public API key ID
    • KALSHI-ACCESS-TIMESTAMP: Unix timestamp in milliseconds
    • KALSHI-ACCESS-SIGNATURE: Base64-encoded signature

💡 Technical Details

Signature Algorithm: RSA-PSS with SHA-256 hashing

Timestamp Format: Unix epoch in milliseconds (13 digits)

3. Step-by-Step Implementation

Step 1: Get API Credentials

Log into Kalshi via a browser (not the mobile app) and navigate to Account & Security and then scroll down to API Keys and select Create Key. Nickname it, select either Read-only or Read and Write, then copy both the API key ID and private key file and save them somewhere safe.

Step 2: Load Your Private Key

Store your private key securely as an environment variable or secret. Do NOT commit it to version control.

# Store in .env file
KALSHI_API_KEY_ID=your-key-id-here
KALSHI_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAo...
-----END PRIVATE KEY-----"

Step 3: Create Signature Function

Implement a function that takes the HTTP method and path, generates a timestamp, creates the message string, signs it with RSA-PSS, and returns the required headers.

Step 4: Sign Each Request

Call your signature function before every API request and include the headers. The signature is only valid for that specific request (timestamp + method + path).

Step 5: Test Your Integration

Start with a simple GET request to /trade-api/v2/portfolio/balance. If you get authentication errors, verify your key format and message construction.

4. Code Examples

Python Example

Using the cryptography library:

import os
import time
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import requests

# Load credentials
API_KEY_ID = os.environ['KALSHI_API_KEY_ID']
PRIVATE_KEY_PEM = os.environ['KALSHI_PRIVATE_KEY']
BASE_URL = 'https://trading-api.kalshi.com'

# Parse private key
private_key = serialization.load_pem_private_key(
    PRIVATE_KEY_PEM.encode(),
    password=None
)

def create_signature(method: str, path: str):
    """Generate Kalshi API signature headers"""
    timestamp = str(int(time.time() * 1000))
    message = f"{timestamp}{method}{path}"

    # Sign with RSA-PSS
    signature = private_key.sign(
        message.encode(),
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )

    # Base64 encode
    signature_b64 = base64.b64encode(signature).decode()

    return {
        'KALSHI-ACCESS-KEY': API_KEY_ID,
        'KALSHI-ACCESS-TIMESTAMP': timestamp,
        'KALSHI-ACCESS-SIGNATURE': signature_b64
    }

# Example: Get portfolio balance
method = 'GET'
path = '/trade-api/v2/portfolio/balance'
headers = create_signature(method, path)

response = requests.get(f"{BASE_URL}{path}", headers=headers)
print(response.json())

Node.js/TypeScript Example

Using Node's built-in crypto module:

import crypto from 'crypto';
import axios from 'axios';

const API_KEY_ID = process.env.KALSHI_API_KEY_ID!;
const PRIVATE_KEY_PEM = process.env.KALSHI_PRIVATE_KEY!;
const BASE_URL = 'https://trading-api.kalshi.com';

function createSignature(method: string, path: string) {
  const timestamp = Date.now().toString();
  const message = `${timestamp}${method}${path}`;

  // Sign with RSA-PSS
  const signature = crypto.sign(
    'sha256',
    Buffer.from(message),
    {
      key: PRIVATE_KEY_PEM,
      padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
      saltLength: crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN,
    }
  );

  // Base64 encode
  const signatureB64 = signature.toString('base64');

  return {
    'KALSHI-ACCESS-KEY': API_KEY_ID,
    'KALSHI-ACCESS-TIMESTAMP': timestamp,
    'KALSHI-ACCESS-SIGNATURE': signatureB64,
  };
}

// Example: Get portfolio fills
async function getPortfolioFills() {
  const method = 'GET';
  const path = '/trade-api/v2/portfolio/fills';
  const headers = createSignature(method, path);

  const response = await axios.get(`${BASE_URL}${path}`, { headers });
  return response.data;
}

getPortfolioFills().then(data => console.log(data));

5. Common Pitfalls

❌ Using JWT Instead of RSA-PSS

Kalshi does NOT use JWT tokens. You must use RSA-PSS signature algorithm with SHA-256. Libraries like jsonwebtoken will not work.

❌ Modifying the Private Key Format

Use the private key exactly as downloaded. Do not strip newlines, remove headers/footers, or reformat it. The key should include -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY-----.

❌ Wrong Message Format

The message MUST be exactly: timestamp + method + path. No spaces, no separators, uppercase method. Path must include query parameters if present.

❌ Timestamp Format

Timestamp must be Unix epoch in milliseconds (13 digits), not seconds (10 digits). Use Date.now() in JavaScript or int(time.time() * 1000) in Python.

6. Quick Reference

API Base URL

https://trading-api.kalshi.com

Required Headers

  • KALSHI-ACCESS-KEY: <your-api-key-id>
  • KALSHI-ACCESS-TIMESTAMP: <unix-ms>
  • KALSHI-ACCESS-SIGNATURE: <base64-signature>

Message Format

timestamp + method + path

Signature Algorithm

RSA-PSS with SHA-256

Salt Length

PSS.MAX_LENGTH (auto-calculate from key)

Ready to analyze your Kalshi trades?

AfterTrade imports your trading history and provides AI-powered coaching feedback to help you improve your performance and find your edge.

Get Started Free →