// GUIDE — MACOS

Kalshi CLI Setup on macOS

May 21, 2026 · Yeti Games, LLC · 8 min read

Getting the Kalshi CLI running on macOS involves three separate problems that aren't documented anywhere official: a corrupted key error, a hardcoded production URL in demo mode, and a silent bug that makes your positions invisible. This guide covers all three.

1. Directory and Credential Setup

Store credentials in a hidden directory with restricted permissions:

mkdir -p ~/.kalshi
touch ~/.kalshi/.env
chmod 700 ~/.kalshi

Add to ~/.zshrc:

export KALSHI_ACCESS_KEY="your-uuid-here"
export KALSHI_PRIVATE_KEY_PATH="/Users/yourname/.kalshi/private_key.pem"
export KALSHI_ENVIRONMENT="demo"

Run source ~/.zshrc after saving.

⚠ KALSHI_ACCESS_KEY must be the UUID from the Kalshi dashboard — not the key's display name. They look similar but only the UUID authenticates correctly.

2. Fixing the InvalidByte Error

If you copy your private key from a browser, hidden characters or smart quotes often corrupt the PEM file. The CLI throws:

ValueError: InvalidData(InvalidByte(4, 95))

Fix by converting to clean PKCS#8 format with OpenSSL:

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
  -in ~/.kalshi/private_key.pem \
  -out ~/.kalshi/private_key_fixed.pem

mv ~/.kalshi/private_key_fixed.pem ~/.kalshi/private_key.pem
chmod 600 ~/.kalshi/private_key.pem

This strips formatting artifacts and outputs a standard key the library accepts. If you don't have OpenSSL, install via Homebrew: brew install openssl.

3. Fixing the NOT_FOUND Error (Demo Mode)

If you're using demo credentials and the CLI returns NOT_FOUND on every request, the CLI is hitting the production server. Some builds are hardcoded to production.

Patch cli.py to read your environment variable:

import os

KALSHI_ENV = os.getenv("KALSHI_ENVIRONMENT", "prod").lower()

if KALSHI_ENV == "demo":
    BASE_URL = "https://external-api.demo.kalshi.co"
else:
    BASE_URL = "https://api.elections.kalshi.com"

Then add aliases to ~/.zshrc for easy switching:

alias kalshi-demo='export KALSHI_ENVIRONMENT=demo && echo "→ DEMO"'
alias kalshi-prod='export KALSHI_ENVIRONMENT=prod && echo "→ PRODUCTION"'

Run kalshi-demo before any paper trading session. Run kalshi-prod when trading real money.

4. Fixing the Missing Positions Bug

Symptom: kalshi positionsprints "No open positions" even when you have open trades.

Cause: Kalshi changed their API response format. The position field (integer) was replaced by position_fp (string like "14"). The CLI filters out positions where position == 0 — and since the old integer field is now missing, everything reads as zero and gets dropped.

Find cli.py — usually in ~/.local/share/kalshi-cli/ — and replace the two lines that load positions:

# Before (original two lines):
ps = data.get("market_positions", [])
ps = [p for p in ps if p.get("position", 0) != 0]

# After (replace with this block):
ps = data.get("market_positions", [])
for p in ps:
    if p.get("position", 0) == 0 and p.get("position_fp"):
        try:
            p["position"] = int(float(p["position_fp"]))
        except (ValueError, TypeError):
            pass
ps = [p for p in ps if p.get("position", 0) != 0]

No restart needed — the CLI reads cli.py fresh on each invocation. Run kalshi positions after the edit to verify.

5. Troubleshooting Checklist

ProblemFix
InvalidByte errorRun the OpenSSL PKCS#8 conversion in Section 2
NOT_FOUND on all requestsCLI hitting production — patch BASE_URL in Section 3
Auth rejectedKALSHI_ACCESS_KEY must be the UUID, not the display name
Key not foundUse absolute paths — never ~/ in env vars
Demo keys on prod serverGenerate keys at demo.kalshi.co, not kalshi.com
kalshi positions shows nothingApply the position_fp backfill patch in Section 4

Next Steps

Once the CLI is working, the next step is running the 5-step AI trading workflow. The Claude Kalshi Playbook ($17) covers the full process — from scanning for opportunities with /alpha to executing trades with /finalize.

← ALL ARTICLESYETI_GAMES.LLCWindows Setup →