API reference

Plan2API API reference

Plan2API is an OpenAI-compatible API at https://api.plan2api.com/v1 with 4 endpoints: chat completions, models, image generations and image edits. Send your p2a_ key as Authorization: Bearer and pick the subscription with the model prefix: claude/, openai/, gemini/ or kimi/.

Base URL
https://api.plan2api.com/v1
Auth
Authorization: Bearer p2a_
Endpoints
4, all under /v1
Free plan
50 chat requests a day

Updated

Base URL, keys and a first request

The base URL is https://api.plan2api.com/v1, the same format as OpenAI's, so any OpenAI client works by changing the base URL and key. Send the key in the Authorization: Bearer header; sending x-api-key is refused with HTTP 401 invalid_api_key.

Keys look like p2a_ followed by a 16-character key id, an underscore and a 43-character secret. You get your first key when you sign up and connect a subscription, and a new key is shown only once. You can create, rename and revoke keys on the Keys page at plan2api.com/dashboard/keys (up to 2 keys on Free, 10 on Pro, and 50 on Scale). The request below reads your key from the PLAN2API_KEY environment variable and calls Claude through the Chat Completions endpoint.

curl
curl https://api.plan2api.com/v1/chat/completions \
  -H "Authorization: Bearer $PLAN2API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude/claude-sonnet-5",
    "messages": [
      {"role": "user", "content": "Write a haiku about base URLs."}
    ]
  }'

Endpoints

The table below lists the four endpoints served under /v1.

Anything else under /v1, including /v1/responses, /v1/messages, /v1/completions and /v1/embeddings, returns HTTP 404 not_found, so tools must use Chat Completions. All four served endpoints return Access-Control-Allow-Origin: * on both normal responses and errors like 401 and 429, answer OPTIONS preflight requests with 204 (allowing methods GET, POST, OPTIONS and headers Authorization, Content-Type, cached for 86400 seconds), and expose Retry-After, x-plan2api-requests-remaining and x-plan2api-requests-reset to browser code.

Browser apps can call the API directly, but a key in browser code is visible to anyone who loads the page, so only ship it in code you don't publish.

Plan2API endpoints
EndpointWhat it doesPlans
POST /v1/chat/completionsChat Completions, streaming or notFree, Pro, Scale
GET /v1/modelsLists every model id Plan2API servesFree, Pro, Scale
POST /v1/images/generationsText to image with gpt-image-2Pro, Scale
POST /v1/images/editsEdits up to 5 source imagesPro, Scale

Model ids and prefixes

The table below shows how model prefixes route requests to your connected subscriptions.

For Claude, the 9 model ids are claude/claude-opus-5-5, claude/claude-fable-5-1, claude/claude-opus-5, claude/claude-sonnet-5, claude/claude-fable-5, claude/claude-opus-4-8 and claude/claude-opus-4-7 (each with a 1,000,000-token context window and up to 128,000 output tokens), plus claude/claude-sonnet-4-6 (200,000 context, 128,000 output) and claude/claude-haiku-4-5 (200,000 context, 64,000 output). The 5 Gemini ids are gemini/gemini-4-argon-high, gemini/gemini-3.8-flash-high, gemini/gemini-3-flash, gemini/gemini-3.5-flash-lite and gemini/gemini-3.1-flash-lite, each with a 1,048,576-token context and text, image, audio and video input. Codex model ids are read live from ChatGPT as openai/<model>, such as openai/gpt-6.1-sol, openai/gpt-6-astra and openai/gpt-6-luna. Kimi serves kimi/k3 (or moonshotai/kimi-k3), which starts on the 256K window and moves to the 1M window when a conversation passes about 192K tokens.

A model id without a prefix goes straight to Codex, so always prefix Claude, Gemini and Kimi ids. Sending an unknown prefix or id returns HTTP 400 model_not_found. Calling GET /v1/models lists every model Plan2API serves, including providers you haven't connected yet, along with context_length, modalities, supported_parameters and accepted reasoning efforts; calling a model whose provider isn't connected returns HTTP 403 no_credentials.

Model prefixes and the subscription each one uses
PrefixSubscriptionExample idContext window
claude/ or anthropic/Claude Pro or Maxclaude/claude-sonnet-51,000,000
openai/ or codex/ChatGPT plan (Codex)openai/gpt-6.1-solListed by GET /v1/models
gemini/, google/ or antigravity/Google AI Pro or Ultragemini/gemini-3.8-flash-high1,048,576
kimi/ or moonshotai/Kimi Code membershipkimi/k31,048,576

Chat completion parameters by provider

The table below covers how each provider handles standard Chat Completions parameters.

Both reasoning_effort and OpenRouter-style reasoning.effort are accepted, and reasoning.effort wins when both are sent, except on Kimi where reasoning_effort wins. Between token limit fields, max_completion_tokens wins over max_tokens, and Claude models default to 128,000 output tokens (or 64,000 on claude-haiku-4-5). System and developer messages are joined into Claude's system prompt, Codex's instructions and Gemini's system instruction, while Kimi receives the messages as sent. For image inputs, Plan2API fetches image URLs in messages for Claude, Gemini and Kimi models (up to 32 per request, up to 20 MB and 15 seconds each, public addresses only), while Codex passes image URLs to ChatGPT as sent; request bodies can be up to 64 MB, and anything larger returns HTTP 413.

How each provider treats Chat Completions parameters
ParameterClaudeCodexGeminiKimi
temperature, top_pIgnoredIgnoredPassed throughFixed at 1 and 0.95
reasoning_effortnone to maxPassed onnone to maxlow, high or max
max_completion_tokensDefault 128,000UsedNot on gemini-* idsUsed
response_format JSON400 unsupported_parameterSupportedgemini-* ids onlyPassed through
tools, tool_choiceFunction toolsFunction toolsSupportedSupported
parallel_tool_callsIgnoredHonouredIgnoredIgnored
stopIgnoredIgnoredUsedIgnored
n, seed, userIgnoredIgnoredIgnoredIgnored

Streaming and the OpenAI SDKs

Setting stream: true returns server-sent events ending with data: [DONE]. The usage object (prompt_tokens, completion_tokens, total_tokens, cached and reasoning token details, and a cost that is always 0) is always attached to the final chunk, so you don't need stream_options.include_usage, and model thinking streams as delta.reasoning. If an error happens after streaming starts, it arrives as a final chunk with finish_reason set to error and a top-level error object, followed by data: [DONE], and both OpenAI SDKs raise APIError for it. A non-streaming request still running after 90 seconds gets its HTTP 200 status sent early with whitespace padding, and a failure after that point comes back as an error object inside a 200 body, so check the body too.

Both openai-python 3.41.0 (using base_url) and openai-node 7.45.1 (using baseURL) work out of the box, read OPENAI_BASE_URL, and default to a 10-minute timeout with 2 automatic retries on connection errors, 408, 409, 429 and 5xx responses. Make sure to call client.chat.completions.create, because the Responses API that the SDK READMEs now open with isn't served. The Python example below streams a Claude reply and prints the token count from the final chunk.

Python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.plan2api.com/v1",
    api_key=os.environ["PLAN2API_KEY"],
)

stream = client.chat.completions.create(
    model="claude/claude-sonnet-5",
    messages=[{"role": "user", "content": "Explain HPKE in two sentences."}],
    reasoning_effort="low",
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:
        print(f"\n{chunk.usage.total_tokens} tokens")

Image generation and edits

POST /v1/images/generations and POST /v1/images/edits run gpt-image-2 on your connected ChatGPT (Codex) subscription on Pro and Scale plans, while Free returns HTTP 403 with type plan_limit and code images before reading the request body. You can pass a prompt up to 32,000 characters, n from 1 to 4, size as auto or WIDTHxHEIGHT where only the aspect ratio counts (from 1:3 to 3:1, about 1.57 megapixels), and background as opaque, transparent or auto. Images come back as b64_json PNG only, and passing stream, mask, or another response_format or output_format returns HTTP 400; edits accept up to 5 PNG, JPEG or WebP files as multipart image or image[] fields, or data URLs in a JSON images array, never remote URLs.

A render takes about 15 to 45 seconds and up to about 110 seconds at high quality; at 90 seconds the HTTP 200 status is sent early and the connection is kept alive, so keep custom client timeouts above 2 minutes (the SDKs' 10-minute default is fine). Image calls appear in your logs and usage, valued at gpt-image-2 list prices, and you can read more in the gpt-image-2 API guide. The Node example below generates and saves a 3:2 image using the OpenAI Node SDK.

Node
import fs from "node:fs";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.plan2api.com/v1",
  apiKey: process.env.PLAN2API_KEY,
  timeout: 300_000,
});

const result = await client.images.generate({
  model: "gpt-image-2",
  prompt: "A lighthouse at dusk, flat vector style",
  size: "1536x1024",
  n: 1,
});

fs.writeFileSync("lighthouse.png", Buffer.from(result.data[0].b64_json, "base64"));

Errors and rate limits

Every error response uses the shape {"error": {"message", "type", "code"}}, where type equals code except on plan limits, which set type to plan_limit.

Beyond the codes in the table, HTTP 400 context_length_exceeded means the prompt is longer than the model's window, HTTP 502 upstream_transient, upstream_unauthorized, upstream_forbidden or upstream_dead means the provider failed or a login needs reconnecting, HTTP 503 no_subscription_available or provider_unavailable means no usable subscription is available right now, and HTTP 500 internal_error marks an unexpected server failure. You can read more about how keys and connected logins are protected.

Rate limits are shared across all keys on an account: Free allows 1 request per second with bursts of 20, 4 at once and 50 chat requests a day; Pro allows 10 per second with bursts of 600 and 16 at once; Scale allows 10 per second with bursts of 600 and 32 at once (see plan limits and pricing). The daily cap on Free counts only POST /v1/chat/completions, never GET /v1/models or image calls, and gives back requests that never reached a provider. On Free, chat responses include x-plan2api-requests-remaining and x-plan2api-requests-reset (the ISO 8601 time of the next reset at 00:00 UTC), and Retry-After values are in seconds.

Common Plan2API error codes
StatusCodeMeaning
400model_not_foundUnknown model id or prefix
400unsupported_parameterJSON response_format on a Claude model
401invalid_api_keyMissing or wrong key, or sent as x-api-key
403no_credentialsNo connected subscription for that provider
403images (plan_limit)Image endpoints on the Free plan
413invalid_requestRequest body over 64 MB
429daily_requests (plan_limit)51st Free chat request of the day
429rate, inflight, rate_limitedOver the per-second or at-once limit
429subscription_quota_exhaustedEvery connected account is out of quota
429subscription_throttledThe provider is rate limiting

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

What is the Plan2API base URL?

The base URL is https://api.plan2api.com/v1, and you authenticate by sending your p2a_ key in an Authorization: Bearer header. Any OpenAI-compatible client or SDK works when configured with those two values.

Does Plan2API support the Responses API or Anthropic's Messages API?

No. Plan2API serves Chat Completions, models and images, while requests to /v1/responses and /v1/messages return HTTP 404 not_found.

Can I call Plan2API from browser JavaScript?

Yes. The API allows every origin (a wildcard Access-Control-Allow-Origin header) and answers OPTIONS preflights with HTTP 204, though anyone who loads your page can read an API key shipped in browser code.

How do I see how many Free requests are left today?

Read the x-plan2api-requests-remaining header on chat completion responses. The x-plan2api-requests-reset header gives the ISO 8601 timestamp for the next reset at 00:00 UTC.

Which models support JSON mode?

Codex, Kimi and Gemini models support JSON mode (json_object and json_schema). Claude models return HTTP 400 unsupported_parameter if you pass a non-text response_format.

Does Plan2API charge per token?

No. Plan2API plans are flat-rate, the response usage object always reports a cost of 0, and your own connected subscription's usage limits apply.

Sources

  1. OpenAI Python SDK (GitHub)github.com
  2. OpenAI Node SDK (GitHub)github.com
  3. MDN: Using server-sent eventsdeveloper.mozilla.org
  4. MDN: Cross-Origin Resource Sharing (CORS)developer.mozilla.org
  5. MDN: Retry-After headerdeveloper.mozilla.org