Skip to main content
The official Anthropic SDK can point to OpenPAI simply by overriding base_url.

Python

pip install anthropic
from anthropic import Anthropic

client = Anthropic(
    api_key="sk-XXXXXXXXXXXXXXXX",      # your OpenPAI key
    base_url="https://openp.ai",         # note: without /v1
)

resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    system="You are a Python engineer",
    messages=[{"role": "user", "content": "Write an LRU Cache in Python"}],
)
print(resp.content[0].text)

Node.js / TypeScript

npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.OPENPAI_API_KEY!,
  baseURL: "https://openp.ai",
});

const resp = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 1024,
  messages: [{ role: "user", content: "hello" }],
});

Streaming

with client.messages.stream(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Tell a story"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Tool calling

resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=[{
        "name": "get_weather",
        "description": "Get a city's weather",
        "input_schema": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        }
    }],
    messages=[{"role": "user", "content": "Check today's weather in Shanghai"}],
)
for block in resp.content:
    if block.type == "tool_use":
        print(block.name, block.input)

Thinking mode

resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=4096,
    thinking={"type": "enabled", "budget_tokens": 8000},
    messages=[{"role": "user", "content": "Prove Fermat's little theorem"}],
)
for block in resp.content:
    if block.type == "thinking":
        print("[thinking]", block.thinking)
    elif block.type == "text":
        print("[answer]", block.text)

Prompt caching

resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "<long system prompt>",
            "cache_control": {"type": "ephemeral"},
        }
    ],
    messages=[{"role": "user", "content": "..."}],
)
See Cache billing.

Vision

resp = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {"type": "image", "source": {
                "type": "base64",
                "media_type": "image/png",
                "data": "<base64-string>",
            }},
        ],
    }],
)

Notes

  • OpenPAI also supports calling Claude via the OpenAI-compatible protocol (/v1/chat/completions), but if your code already uses the Anthropic SDK, overriding base_url is the lowest-change option.
  • The anthropic-version header is added automatically by the SDK; you don’t need to specify it manually.
  • The upstream official Anthropic API isn’t open to all regions yet — OpenPAI provides stable access.