A Python wrapper and HTTP API for the Claude Code CLI.
Access Claude models through the Claude Code binary without direct API key management. Authentication is handled automatically via Claude Code's OAuth flow.
# Install Claude Code CLI
npm install -g @anthropic-ai/claude-code
claude auth login
# Clone and run
git clone https://github.com/drpedapati/claude-code-api.git
cd claude-code-api
make server
# Test it
curl http://localhost:7742/health
curl -X POST http://localhost:7742/llm/chat \
-H "Content-Type: application/json" \
-d '{"prompt": "What is 2+2?", "model": "haiku"}'git clone https://github.com/drpedapati/claude-code-api.git
cd claude-code-api
# Using uv (fast)
uv sync
# Or pip
pip install -e ".[all]"pip install git+https://github.com/drpedapati/claude-code-api.gitfrom claude_code_api import ClaudeClient, claude_chat, claude_json
# Initialize a client
client = ClaudeClient(model="haiku")
# Simple chat
result = client.chat("What is the capital of France?")
print(result.text) # "Paris"
# Get structured JSON response
data = client.chat_json(
"What are the first 5 prime numbers?",
system="Return JSON: {primes: [numbers]}"
)
print(data["primes"]) # [2, 3, 5, 7, 11]
# Convenience functions for one-off queries
response = claude_chat("What is 2+2?")
data = claude_json("List 3 colors", system="Return JSON: {colors: [strings]}")# Start server (port 7742)
make server
# Or directly
uvicorn claude_code_api.server:app --host 0.0.0.0 --port 7742| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/llm/status |
Claude CLI availability |
GET |
/llm/models |
List available models |
POST |
/llm/chat |
Text response |
POST |
/llm/chat/stream |
Streaming response (SSE) |
POST |
/llm/json |
JSON response |
POST |
/llm/query |
Full SDK query with images, tools, sessions |
POST |
/llm/query/stream |
Streaming query with token-level updates |
POST |
/llm/query/async |
Submit async job (returns job_id for polling) |
GET |
/llm/query/async/{job_id} |
Poll for async job result |
POST |
/llm/computer-use |
Computer control (screenshot, click, type) |
# Health check
curl http://localhost:7742/health
# {"status":"ok","service":"claude-code-api","version":"0.1.0"}
# Chat
curl -X POST http://localhost:7742/llm/chat \
-H "Content-Type: application/json" \
-d '{"prompt": "What is 2+2?", "model": "haiku"}'
# {"text":"4","model":"haiku","is_error":false}
# JSON response
curl -X POST http://localhost:7742/llm/json \
-H "Content-Type: application/json" \
-d '{"prompt": "List 3 colors", "system": "Return JSON only: {colors: [strings]}", "model": "haiku"}'
# {"colors":["red","blue","green"]}API Docs: http://localhost:7742/docs
Control your computer through Claude using an agentic loop with screenshots, mouse, and keyboard actions.
# Prerequisites (macOS)
brew install cliclick
# Prerequisites (Linux)
apt install xdotool gnome-screenshot # or scrot
# Example request
curl -N -X POST http://localhost:7742/llm/computer-use \
-H "Content-Type: application/json" \
-d '{
"prompt": "Open the calculator app and compute 15 * 23",
"model": "sonnet",
"max_turns": 10,
"display_width": 1024,
"display_height": 768
}'Available Actions:
- Screenshot capture
- Mouse movement and clicking
- Keyboard typing and key presses
- Scrolling and waiting
Security Note: Computer Use gives Claude control of your computer. Use only in trusted environments or sandboxed VMs.
For complex vision analysis or requests that may take more than 30 seconds, use the async job endpoint to avoid timeouts.
# 1. Submit the job
JOB_RESPONSE=$(curl -s -X POST http://localhost:7742/llm/query/async \
-H "Content-Type: application/json" \
-d '{
"prompt": "Analyze this complex form and extract all fields",
"images": [{"data": "'$(base64 -i form.png)'", "media_type": "image/png"}],
"model": "sonnet"
}')
JOB_ID=$(echo $JOB_RESPONSE | jq -r '.job_id')
echo "Job submitted: $JOB_ID"
# 2. Poll for results
while true; do
STATUS=$(curl -s "http://localhost:7742/llm/query/async/$JOB_ID")
JOB_STATUS=$(echo $STATUS | jq -r '.status')
if [ "$JOB_STATUS" = "completed" ]; then
echo "Done! Result:"
echo $STATUS | jq '.result.text'
break
elif [ "$JOB_STATUS" = "failed" ]; then
echo "Failed: $(echo $STATUS | jq -r '.error')"
break
fi
echo "Status: $JOB_STATUS, waiting..."
sleep 3
doneWhen to use async:
- Large image analysis (multi-MB files)
- Complex multi-image semantic analysis
- Requests expected to take > 30 seconds
- Avoiding gateway timeouts (504 errors)
| Model | API ID | Speed | Pricing (MTok) |
|---|---|---|---|
haiku |
claude-haiku-4-5-20251001 |
Fastest | $1 / $5 |
sonnet |
claude-sonnet-4-5-20250929 |
Balanced | $3 / $15 |
opus |
claude-opus-4-5-20251101 |
Most capable | $5 / $25 |
opus-4-6 |
claude-opus-4-6 |
Most capable | $5 / $25 |
Protect your API with simple key-based authentication.
# Create a new API key
make api-key-create NAME=myapp
# Shows: cca_a1b2c3d4... (save this!)
# List all keys (shows hashes only)
make api-key-list
# Revoke a key
make api-key-revoke HASH=5d41
# Rotate (revoke + create new)
make api-key-rotate HASH=5d41 NAME=myapp-v2# With curl
curl -H "Authorization: Bearer cca_your_key_here" \
http://localhost:7742/llm/chat \
-d '{"prompt": "Hello"}'
# Without key (when .api-keys exists)
# Returns: 401 Unauthorized- Keys are
cca_prefix + 32 random hex chars - Only SHA256 hashes are stored in
.api-keys - If
.api-keysdoesn't exist, auth is disabled /healthand/docsare always public
# Mount keys file
docker run -v $(pwd)/.api-keys:/app/.api-keys ...
# Or via environment (comma-separated hashes)
API_KEY_HASHES="hash1,hash2" make docker-run
# Disable auth entirely
API_AUTH_DISABLED=1 make docker-runInteractive streaming chat demos are included:
# Terminal chat with real-time streaming
make chat
# Web chat with SSE (opens on port 7743)
make chat-web
make chat-web-stopThe examples demonstrate:
- Real-time token streaming via
--include-partial-messages - Async subprocess handling for web servers
- Server-Sent Events (SSE) for browser streaming
# Build and run
make docker-build
make docker-run
# With OAuth token (for authenticated requests)
export CLAUDE_CODE_OAUTH_TOKEN="your-token" # from: claude setup-token
make docker-run
# Test container
make docker-testThe container:
- Runs on port 7742
- Persists Claude data in
claude-code-datavolume - Includes Claude Code CLI pre-installed
Deploy to any server with Kamal 2.9+.
# Install Kamal
gem install kamal
# Configure secrets
cp .kamal/secrets.example .kamal/secrets
# Edit with: KAMAL_REGISTRY_PASSWORD, CLAUDE_CODE_OAUTH_TOKEN
# Set environment
export KAMAL_SERVER_IP="your.server.ip"
export KAMAL_REGISTRY_USERNAME="your-github-username"
export KAMAL_SSH_USER="your-ssh-user"# First time (installs Docker, proxy, etc.)
make kamal-setup
# Deploy updates
make kamal-deploy
# View logs
make kamal-logs
# Rollback
make kamal-rollback- ARM64 VMs: Set
arch: arm64inconfig/deploy.ymlfor Apple Silicon - SSL: Enable via
ssl: truein proxy config when using a domain - Secrets: Stored in
.kamal/secrets(gitignored)
# Install with dev dependencies
make dev
# Run tests
make test # All tests
make test-quick # Unit tests only (no CLI)
make test-gist # SDK spec tests
# Code quality
make lint # Check code
make format # Format code
make typecheck # Type check
# Status
make status # Check server status
make help # All commands| Command | Description |
|---|---|
make server |
Start API server (port 7742) |
make stop |
Stop server |
make chat |
Interactive terminal chat |
make chat-web |
Web chat (port 7743) |
make api-key-create |
Create new API key |
make api-key-list |
List API keys |
make api-key-revoke |
Revoke a key |
make docker-build |
Build Docker image |
make docker-run |
Run container |
make kamal-deploy |
Deploy to production |
make test |
Run all tests |
make help |
Show all commands |
Authentication is automatic via Claude Code:
- OAuth (recommended):
claude auth login(one-time browser auth) - Token (Docker/CI):
claude setup-tokento generate OAuth token
Note:
ANTHROPIC_API_KEYis automatically removed from the subprocess environment to prevent conflicts with Claude Code's OAuth flow.
- Python 3.10+
- Claude Code CLI (Node.js 18+)
MIT License - see LICENSE for details.
