A lightweight local proxy that exposes Puter.com's AI models through a standard OpenAI-compatible API (/v1/chat/completions). Use Puter's free-tier models (Claude, GPT, Qwen, and more) directly from any OpenAI SDK, agent framework, or code editor that supports custom OpenAI-compatible endpoints.
- How It Works
- Supported Features
- Available Models
- Prerequisites
- Installation
- Getting Your Auth Token
- Configuration
- Running the Proxy
- API Reference
- Integration Guides
- Error Handling
- Troubleshooting
- Project Structure
- Limitations
- License
Your AI Tool Puter Proxy Puter API
(OpenCode, SDK, (localhost:8000) (api.puter.com)
Cursor, etc.)
| | |
| POST /v1/chat/ | |
| completions | |
| (OpenAI format) | |
|---------------------->| |
| | POST /drivers/call |
| | (Puter driver format) |
| |------------------------->|
| | |
| | NDJSON stream |
| |<-------------------------|
| SSE stream / JSON | |
| (OpenAI format) | |
|<----------------------| |
The proxy receives standard OpenAI Chat Completion requests, translates them into Puter's internal driver API format, and translates Puter's NDJSON responses back into OpenAI-compatible SSE streams or JSON responses.
| Feature | Streaming | Non-Streaming | Notes |
|---|---|---|---|
| Text content | Yes | Yes | Standard assistant messages |
| Tool calls (function calling) | Yes | Yes | Single and parallel tool calls |
| Tool call deltas | Yes | N/A | Incremental argument streaming |
| Reasoning / thinking | Yes | Yes | reasoning_content field |
| Structured outputs | Yes | Yes | response_format passthrough |
| Sampling parameters | Yes | Yes | temperature, max_tokens, top_p, etc. |
| Usage statistics | Yes | Yes | Token counts and cost |
| Finish reason | Yes | Yes | stop, tool_calls, length, etc. |
| Error passthrough | Yes | Yes | Upstream status codes preserved (402, 429, etc.) |
All standard OpenAI Chat Completion parameters are forwarded transparently to Puter, including: tools, tool_choice, response_format, temperature, max_tokens, top_p, frequency_penalty, presence_penalty, stop, seed, and any other parameters Puter supports.
The proxy exposes these models by default (configurable in puter_proxy.py):
| Model ID | Provider | Description |
|---|---|---|
claude-fable-5 |
Anthropic | Claude Fable 5 |
claude-opus-4-8 |
Anthropic | Claude Opus 4.8 |
qwen/qwen3.7-max |
Alibaba | Qwen 3.7 Max |
You can use any model available on Puter by specifying its ID in your request. To add models to the /v1/models listing, edit the data array in the models() endpoint.
- Python 3.9+
- A Puter.com account (free tier works)
- A web browser (for extracting the auth token)
-
Clone the repository:
git clone https://github.com/YOUR_USERNAME/puter-proxy.git cd puter-proxy -
Install Python dependencies:
pip install -r requirements.txt
Or install manually:
pip install fastapi uvicorn requests python-dotenv
The proxy needs your Puter auth token to make API calls on your behalf. Here's how to extract it:
From the project directory, start a simple HTTP server:
python -m http.server 8000Navigate to:
http://localhost:8000
This loads the test_puter.html page which includes the Puter JS SDK. Wait for the page to fully load.
Open Developer Tools (press F12 or Ctrl+Shift+I / Cmd+Option+I on Mac), go to the Console tab, and run:
localStorage.getItem("puter.auth.token.v2")If you are not logged in, Puter will prompt you to sign in first. After signing in, run the command again.
Copy the returned token string.
Create a .env file in the project root:
cp .env.example .envThen paste your token:
PUTER_TOKEN=your-token-hereImportant: Never commit your
.envfile or share your token. It is already excluded in.gitignore.
| Variable | Required | Default | Description |
|---|---|---|---|
PUTER_TOKEN |
Yes | - | Your Puter auth token (JWT) |
The proxy runs on:
| Setting | Value |
|---|---|
| Host | 0.0.0.0 (all interfaces) |
| Port | 8000 |
| Base URL | http://localhost:8000/v1 |
To change the port, edit the last line of puter_proxy.py:
uvicorn.run(app, host="0.0.0.0", port=8000) # change 8000 to your preferred portpython puter_proxy.pyYou should see:
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
curl http://localhost:8000/v1/modelsExpected response:
{
"object": "list",
"data": [
{"id": "claude-fable-5", "object": "model", "owned_by": "puter"},
{"id": "claude-opus-4-8", "object": "model", "owned_by": "puter"},
{"id": "qwen/qwen3.7-max", "object": "model", "owned_by": "puter"}
]
}curl -X POST http://localhost:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-opus-4-8",
"messages": [{"role": "user", "content": "hi"}]
}'Returns the list of available models in OpenAI format.
Standard OpenAI Chat Completions endpoint. Accepts all parameters from the OpenAI Chat Completions API.
{
"model": "claude-opus-4-8",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello"}
],
"stream": false,
"temperature": 0.7,
"max_tokens": 1024,
"tools": [...],
"tool_choice": "auto",
"response_format": {"type": "json_object"}
}All parameters except model and messages are optional. Any unrecognized parameters are forwarded to Puter transparently.
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1781115204,
"model": "claude-opus-4-8",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help?",
"reasoning_content": "...",
"tool_calls": [...]
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 28,
"cached_tokens": 0,
"usd_cents": 0.039
}
}When "stream": true, the endpoint returns Server-Sent Events:
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1781115204,"model":"claude-opus-4-8","choices":[{"index":0,"delta":{"reasoning_content":"Thinking..."},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1781115204,"model":"claude-opus-4-8","choices":[{"index":0,"delta":{"content":"Hello!"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1781115204,"model":"claude-opus-4-8","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{...}}
data: [DONE]
Add to your opencode.config.json:
{
"ai": {
"providers": {
"puter": {
"npm": "@ai-sdk/openai-compatible",
"name": "Puter",
"options": {
"baseURL": "http://127.0.0.1:8000/v1",
"apiKey": "dummy"
},
"models": {
"claude-opus-4-8": {},
"qwen/qwen3.7-max": {},
"claude-fable-5": {}
}
}
}
}
}The apiKey value is ignored by the proxy (authentication uses the .env token), but some SDKs require it to be set.
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="dummy"
)
# Non-streaming
response = client.chat.completions.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
# Streaming
stream = client.chat.completions.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": "Hello"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://localhost:8000/v1",
apiKey: "dummy",
});
const response = await client.chat.completions.create({
model: "claude-opus-4-8",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content);Add to your ~/.continue/config.json:
{
"models": [
{
"title": "Puter Claude Opus",
"provider": "openai",
"model": "claude-opus-4-8",
"apiBase": "http://localhost:8000/v1",
"apiKey": "dummy"
},
{
"title": "Puter Qwen Max",
"provider": "openai",
"model": "qwen/qwen3.7-max",
"apiBase": "http://localhost:8000/v1",
"apiKey": "dummy"
}
]
}In Cline settings:
- API Provider: Select "OpenAI Compatible"
- Base URL:
http://localhost:8000/v1 - API Key:
dummy - Model ID:
claude-opus-4-8(or any available model)
In Cursor Settings > Models:
- Add a new OpenAI-compatible provider
- Base URL:
http://localhost:8000/v1 - API Key:
dummy - Model:
claude-opus-4-8
# Non-streaming
curl -X POST http://localhost:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-opus-4-8",
"messages": [{"role": "user", "content": "Explain quantum computing"}]
}'
# Streaming
curl -X POST http://localhost:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-opus-4-8",
"messages": [{"role": "user", "content": "Write a haiku"}],
"stream": true
}'
# With tool calls
curl -X POST http://localhost:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-opus-4-8",
"messages": [{"role": "user", "content": "What is the weather in London?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"]
}
}
}]
}'The proxy passes through Puter's HTTP status codes and error messages:
| Status | Meaning | Example |
|---|---|---|
200 |
Success | Normal response |
402 |
Insufficient funds | Puter usage quota exceeded |
429 |
Rate limited | Too many requests |
500 |
Server error | Token not configured |
502 |
Upstream error | Cannot reach Puter API |
PUTER_TOKEN environment variable not set (HTTP 500)
Your .env file is missing or the token is empty. See Getting Your Auth Token.
No usage left for request (HTTP 402)
Your Puter account has reached its usage limit for the requested model. Options:
- Wait for the quota to reset
- Switch to a different model
- Upgrade your Puter plan
# Check Python version (need 3.9+)
python --version
# Check dependencies
pip install -r requirements.txt- Log out and back in at puter.com
- Re-extract the token using the browser console method
- Update your
.envfile with the new token
The model list in /v1/models is cosmetic. You can request any model available on Puter by specifying its ID directly. If a model returns an error, it may not be available on your Puter plan.
Some tools don't support streaming. Set "stream": false in your request, or check your tool's documentation for streaming configuration.
puter-proxy/
puter_proxy.py # Main proxy server (FastAPI)
.env # Your auth token (not committed)
.env.example # Template for .env
.gitignore # Git ignore rules
requirements.txt # Python dependencies
test_puter.html # Helper page for token extraction
package.json # Node.js deps (Puter JS SDK for token page)
README.md # This file
- Single-user: The proxy is designed for local, single-user use. It uses one auth token for all requests.
- No authentication: The proxy has no auth layer. Anyone who can reach
localhost:8000can make requests. Do not expose it to the internet. - Puter rate limits: Free-tier Puter accounts have usage limits per model. Heavy use (especially with agent frameworks that make many requests) may hit these limits.
- Model availability: Available models depend on your Puter account tier. The models listed in
/v1/modelsare suggestions; actual availability may vary.
MIT