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.
| Setting | SDK (completion) | Proxy (config.yaml) |
|---|---|---|
| Model | model="openai/ | litellm_ |
| Base URL | api_ | litellm_ |
| API key | api_ | api_ |
| Name clients send | Not needed | model_ |
| Client auth | Not needed | general_ |
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 | Sent to Plan2API as | Subscription |
|---|---|---|
| openai/ | claude/ | Claude Pro or Max |
| openai/ | claude/ | Claude Pro or Max |
| openai/ | openai/ | ChatGPT (Codex) |
| openai/ | gemini/ | Google AI Pro or Ultra |
| openai/ | kimi/ | Kimi Code |
Call Plan2API from the LiteLLM SDK
- Sign up with a Google account, connect your Claude, ChatGPT, Google AI, or Kimi subscription, and copy your
p2a_API key from the dashboard. - Install the SDK in your Python environment with
pip install litellm. - Export your key in the shell as
export PLAN2API_KEY="p2a_..."so your code can read it from the environment. - Import
completionfromlitellmand call it with youropenai/model string,api_base="https://api.plan2api.com/v1", andapi_key=os.environ["PLAN2API_KEY"]. - For streaming responses, pass
stream=Truetocompletion()and iterate over the returned chunks, reading the text frompart.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.
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
- Install the proxy CLI with
uv tool install 'litellm[proxy]'(LiteLLM1.84.0and newer require Python 3.10 or later). - Save the YAML configuration shown below as
config.yamlin your working directory. - Export both
PLAN2API_KEY(yourp2a_key) andLITELLM_MASTER_KEY(the bearer token your internal clients will send to the proxy) in the shell environment. - Start the server with
litellm --config config.yamland wait for theLiteLLM: Proxy initialized with Config, Set models:line in the logs. - Point any OpenAI-compatible SDK or tool at
http://0.0.0.0:4000, authenticate with yourLITELLM_MASTER_KEYin theAuthorization: Bearerheader, and pass amodel_namefrom your config such asclaude-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.
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_KEYWhat 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 asyncacompletion()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 onopenai/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/completionsand/modelsroutes. - Codex models staying on
/v1/chat/completions, becausegpt-6.1-solis marked aschatmode in LiteLLM's cost map andlitellm.route_all_chat_openai_to_responsesis off by default, unless a call combines function tools withreasoning_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/embeddingsroute, as there is no/v1/embeddingsendpoint.- The
text-completion-openai/provider prefix and the proxy's/completionsroute, as there is no legacy/v1/completionsendpoint. - Codex calls that send function tools together with
reasoning_effort, because for GPT-5.4 and newer ids such asopenai/openai/gpt-6.1-solLiteLLM moves those requests to the Responses API (/v1/responses), which Plan2API doesn't have, so leavereasoning_effortoff on Codex tool calls. - Non-text
response_formatvalues (json_objectorjson_schema) on Claude models, which return HTTP 400unsupported_parametereven if you setlitellm_settings: drop_params: true(LiteLLM still forwardsresponse_formatonopenai/models).
Troubleshooting LiteLLM with Plan2API
401 invalid_api_key:PLAN2API_KEYisn't exported in the shell environment actually running your Python process or proxy, or the key value is wrong. Checkos.environ["PLAN2API_KEY"]and make sure it starts withp2a_.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 firstopenai/slash doesn't match a known model id. QueryGET /v1/modelsagainsthttps://api.plan2api.com/v1to see the exact ids available to your key, and remember to keep the provider prefix (such asopenai/gemini/gemini-3-flash).400 unsupported_parameter: You passed ajson_objectorjson_schemaresponse_formatto aclaude/oranthropic/model. Settingdrop_params: truein LiteLLM doesn't stripresponse_formatforopenai/providers, so remove the parameter when calling Claude or switch that call to a Codex, Gemini, or Kimi model.Not Found: Yourapi_baseis missing the trailing/v1, causing LiteLLM to post tohttps://api.plan2api.com/chat/completions. Setapi_basetohttps://api.plan2api.com/v1."No connected db."from the proxy: The client callinghttp://0.0.0.0:4000sent an API key other than yourLITELLM_MASTER_KEY(for example, it sent thep2a_key directly to the proxy) while the proxy is running without a database. Send the master key to the proxy, and let the proxy'sconfig.yamlpassos.environ/PLAN2API_KEYupstream.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 theRetry-Afterwindow 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
- LiteLLM OpenAI-compatible endpointsdocs.litellm.ai
- LiteLLM Proxy quick startdocs.litellm.ai
- LiteLLM Proxy config.yamldocs.litellm.ai
- LiteLLM streamingdocs.litellm.ai
- LiteLLM provider parsing (GitHub)github.com
- LiteLLM model cost map (GitHub)github.com
- LiteLLM Responses API bridge check (GitHub)github.com