LiteLLM integration

LiteLLM with Plan2API: SDK calls and a Proxy config.yaml

LiteLLM talks to Plan2API through its openai/ provider in 2 places: completion() in the SDK and model_list in a Proxy config.yaml served on port 4000. Prefix a Plan2API id with openai/, set api_base to https://api.plan2api.com/v1, and one p2a_ key routes Claude, GPT, Gemini and Kimi.

Model string
openai/claude/claude-sonnet-5
api_base
https://api.plan2api.com/v1
Proxy api_key
os.environ/PLAN2API_KEY
Proxy port
4000

Updated

LiteLLM settings for Plan2API

LiteLLM uses its generic openai/ provider to talk to Plan2API, both when you call the Python SDK directly and when you run the LiteLLM Proxy. The table below lists the exact values to pass in your code or config.yaml.

LiteLLM settings for Plan2API
SettingSDK (completion)Proxy (config.yaml)
Modelmodel="openai/claude/claude-sonnet-5"litellm_params.model
Base URLapi_base="https://api.plan2api.com/v1"litellm_params.api_base
API keyapi_key=os.environ["PLAN2API_KEY"]api_key: os.environ/PLAN2API_KEY
Name clients sendNot neededmodel_name, such as claude-sonnet-5
Client authNot neededgeneral_settings.master_key

How the openai/ prefix maps to Plan2API ids

When you pass a model string to LiteLLM, it splits the string at the first slash to pick the provider and sends everything after that first slash as the model field in the request body. Because Plan2API model ids already include a provider prefix (claude/, openai/, codex/, gemini/, or kimi/), you keep that full id and put another openai/ in front of it. To call claude/claude-sonnet-5 through LiteLLM, for instance, you pass openai/claude/claude-sonnet-5, and LiteLLM forwards claude/claude-sonnet-5 to /v1/chat/completions.

Keep /v1 at the end of api_base (https://api.plan2api.com/v1), or LiteLLM posts to /chat/completions at the host root and gets a Not Found error.

Here is how the openai/ prefix combines with each upstream provider's model ids.

LiteLLM model strings for Plan2API
LiteLLM modelSent to Plan2API asSubscription
openai/claude/claude-sonnet-5claude/claude-sonnet-5Claude Pro or Max
openai/claude/claude-opus-5-5claude/claude-opus-5-5Claude Pro or Max
openai/openai/gpt-6.1-solopenai/gpt-6.1-solChatGPT (Codex)
openai/gemini/gemini-3.8-flash-highgemini/gemini-3.8-flash-highGoogle AI Pro or Ultra
openai/kimi/k3kimi/k3Kimi Code

Call Plan2API from the LiteLLM SDK

  1. Sign up with a Google account, connect your Claude, ChatGPT, Google AI, or Kimi subscription, and copy your p2a_ API key from the dashboard.
  2. Install the SDK in your Python environment with pip install litellm.
  3. Export your key in the shell as export PLAN2API_KEY="p2a_..." so your code can read it from the environment.
  4. Import completion from litellm and call it with your openai/ model string, api_base="https://api.plan2api.com/v1", and api_key=os.environ["PLAN2API_KEY"].
  5. For streaming responses, pass stream=True to completion() and iterate over the returned chunks, reading the text from part.choices[0].delta.content.

If your codebase runs on asyncio, import acompletion from litellm and pass the exact same arguments.

The script below runs a standard call and a streaming call against Claude and Gemini.

Python
import os

from litellm import completion

plan2api = {
    "api_base": "https://api.plan2api.com/v1",
    "api_key": os.environ["PLAN2API_KEY"],
}

response = completion(
    model="openai/claude/claude-sonnet-5",
    messages=[{"role": "user", "content": "Summarize RFC 9110 in one sentence."}],
    **plan2api,
)
print(response.choices[0].message.content)

stream = completion(
    model="openai/gemini/gemini-3.8-flash-high",
    messages=[{"role": "user", "content": "Count to five."}],
    stream=True,
    **plan2api,
)
for part in stream:
    print(part.choices[0].delta.content or "", end="")
print()

Run LiteLLM Proxy with a Plan2API model_list

  1. Install the proxy CLI with uv tool install 'litellm[proxy]' (LiteLLM 1.84.0 and newer require Python 3.10 or later).
  2. Save the YAML configuration shown below as config.yaml in your working directory.
  3. Export both PLAN2API_KEY (your p2a_ key) and LITELLM_MASTER_KEY (the bearer token your internal clients will send to the proxy) in the shell environment.
  4. Start the server with litellm --config config.yaml and wait for the LiteLLM: Proxy initialized with Config, Set models: line in the logs.
  5. Point any OpenAI-compatible SDK or tool at http://0.0.0.0:4000, authenticate with your LITELLM_MASTER_KEY in the Authorization: Bearer header, and pass a model_name from your config such as claude-sonnet-5.

In the config.yaml below, each model_name is the short alias your clients send to port 4000, while litellm_params.model holds the full openai/ string that LiteLLM sends upstream.

YAML
model_list:
  - model_name: claude-sonnet-5
    litellm_params:
      model: openai/claude/claude-sonnet-5
      api_base: https://api.plan2api.com/v1
      api_key: os.environ/PLAN2API_KEY
  - model_name: gpt-6.1-sol
    litellm_params:
      model: openai/openai/gpt-6.1-sol
      api_base: https://api.plan2api.com/v1
      api_key: os.environ/PLAN2API_KEY
  - model_name: gemini-flash
    litellm_params:
      model: openai/gemini/gemini-3.8-flash-high
      api_base: https://api.plan2api.com/v1
      api_key: os.environ/PLAN2API_KEY
  - model_name: kimi-k3
    litellm_params:
      model: openai/kimi/k3
      api_base: https://api.plan2api.com/v1
      api_key: os.environ/PLAN2API_KEY

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY

What works through LiteLLM and what doesn't

Although Plan2API already acts as an LLM gateway that puts several providers behind one p2a_ key, teams already running LiteLLM in their stack can rely on these features working end to end:

  • Synchronous completion() and async acompletion() calls in the Python SDK.
  • Streaming responses (stream=True) over server-sent events.
  • Tool and function calling across Claude, Codex, Gemini, and Kimi models.
  • Reasoning effort via reasoning_effort, which LiteLLM forwards straight through on openai/ models.
  • Image inputs on Claude, Gemini, and Kimi models, plus Codex models that accept images (up to 32 image URLs per request, up to 20 MB and 15 seconds each).
  • The proxy's /chat/completions and /models routes.
  • Codex models staying on /v1/chat/completions, because gpt-6.1-sol is marked as chat mode in LiteLLM's cost map and litellm.route_all_chat_openai_to_responses is off by default, unless a call combines function tools with reasoning_effort (see below).

These LiteLLM features and routes will fail because the upstream endpoints or parameters aren't supported:

  • embedding() in the SDK and the proxy's /embeddings route, as there is no /v1/embeddings endpoint.
  • The text-completion-openai/ provider prefix and the proxy's /completions route, as there is no legacy /v1/completions endpoint.
  • Codex calls that send function tools together with reasoning_effort, because for GPT-5.4 and newer ids such as openai/openai/gpt-6.1-sol LiteLLM moves those requests to the Responses API (/v1/responses), which Plan2API doesn't have, so leave reasoning_effort off on Codex tool calls.
  • Non-text response_format values (json_object or json_schema) on Claude models, which return HTTP 400 unsupported_parameter even if you set litellm_settings: drop_params: true (LiteLLM still forwards response_format on openai/ models).

Troubleshooting LiteLLM with Plan2API

  • 401 invalid_api_key: PLAN2API_KEY isn't exported in the shell environment actually running your Python process or proxy, or the key value is wrong. Check os.environ["PLAN2API_KEY"] and make sure it starts with p2a_.
  • 403 no_credentials: Your vault doesn't have a connected subscription for the provider prefix you requested. Open the dashboard and connect a Claude, ChatGPT, Google AI, or Kimi account for that model family.
  • 400 model_not_found: The string after the first openai/ slash doesn't match a known model id. Query GET /v1/models against https://api.plan2api.com/v1 to see the exact ids available to your key, and remember to keep the provider prefix (such as openai/gemini/gemini-3-flash).
  • 400 unsupported_parameter: You passed a json_object or json_schema response_format to a claude/ or anthropic/ model. Setting drop_params: true in LiteLLM doesn't strip response_format for openai/ providers, so remove the parameter when calling Claude or switch that call to a Codex, Gemini, or Kimi model.
  • Not Found: Your api_base is missing the trailing /v1, causing LiteLLM to post to https://api.plan2api.com/chat/completions. Set api_base to https://api.plan2api.com/v1.
  • "No connected db." from the proxy: The client calling http://0.0.0.0:4000 sent an API key other than your LITELLM_MASTER_KEY (for example, it sent the p2a_ key directly to the proxy) while the proxy is running without a database. Send the master key to the proxy, and let the proxy's config.yaml pass os.environ/PLAN2API_KEY upstream.
  • 429 daily_requests: You hit the 51st chat request of the day on the Free plan, which caps usage at 50 chat requests per day and resets at 00:00 UTC. Wait for the Retry-After window to pass, or check the Plan2API pricing and plan limits to move to Pro ($12 a month) or Scale ($29 a month), which have no daily request cap.

Once a streaming response has started, any mid-stream error is delivered as a final server-sent event in the stream rather than an HTTP status code.

Use the AI subscriptions you already pay for as one OpenAI-compatible API key.

  • Free: 1 subscription, 50 requests a day, no card
  • Pro: $12 a month

FAQ

How do I use an OpenAI-compatible API in LiteLLM?

Prefix the model name with openai/, set api_base to the server's base URL ending in /v1, and pass your key in api_key. That same pattern works in both litellm.completion() and a LiteLLM Proxy config.yaml.

Does LiteLLM strip the openai/ prefix?

Yes, LiteLLM strips only the first path segment before sending the request. When you pass openai/claude/claude-sonnet-5, LiteLLM uses openai to select its OpenAI-compatible client and sends claude/claude-sonnet-5 as the model in the JSON body to Plan2API.

Can LiteLLM Proxy serve Claude from a Claude Pro or Max plan?

Yes, when you connect your Claude Pro or Max account to Plan2API and put openai/claude/ model ids (such as openai/claude/claude-sonnet-5 or openai/claude/claude-opus-5-5) into your proxy's model_list. Your apps and developers authenticate against the LiteLLM Proxy using its LITELLM_MASTER_KEY, and the proxy routes those requests through your p2a_ key.

Does drop_params fix response_format errors on Claude?

No. For models routed through the openai/ provider, LiteLLM forwards response_format even when drop_params: true is enabled, and Claude models reject non-text response_format values with 400 unsupported_parameter. Remove response_format on Claude calls, or route structured JSON requests to a Gemini, Codex, or Kimi model where json_object and json_schema are supported.

Do embeddings work through LiteLLM and Plan2API?

No. Plan2API does not expose a /v1/embeddings endpoint, so calling litellm.embedding() or hitting the proxy's /embeddings route will fail.

Sources

  1. LiteLLM OpenAI-compatible endpointsdocs.litellm.ai
  2. LiteLLM Proxy quick startdocs.litellm.ai
  3. LiteLLM Proxy config.yamldocs.litellm.ai
  4. LiteLLM streamingdocs.litellm.ai
  5. LiteLLM provider parsing (GitHub)github.com
  6. LiteLLM model cost map (GitHub)github.com
  7. LiteLLM Responses API bridge check (GitHub)github.com