LangChain integration

LangChain with Plan2API: Gemini, Claude, GPT and Kimi through ChatOpenAI

LangChain's ChatOpenAI runs 5 Gemini models, 9 Claude models, GPT and Kimi through Plan2API: set base_url to https://api.plan2api.com/v1, pass a p2a_ key and add use_responses_api=False. Gemini ids get the full 1,048,576-token context with no Gemini API key.

Python package
langchain-openai
JS package
@langchain/openai
base_url
https://api.plan2api.com/v1
Python switch
use_responses_api=False

Updated

LangChain settings for Plan2API

ChatOpenAI is the only class you need to talk to Plan2API, whether you're writing Python or JavaScript. In Python, if you don't pass explicit arguments, ChatOpenAI reads your key from OPENAI_API_KEY and checks OPENAI_API_BASE, then OPENAI_BASE_URL for the custom endpoint. The table below covers the arguments and environment variables you'll use.

ChatOpenAI settings for Plan2API
SettingPythonJavaScript
Packagelangchain-openai@langchain/openai
Base URLbase_url="https://api.plan2api.com/v1"configuration: { baseURL }
API keyapi_key=os.environ["PLAN2API_KEY"]apiKey: process.env.PLAN2API_KEY
Modelmodel="gemini/gemini-3.8-flash-high"model: "gemini/gemini-3.8-flash-high"
Stay on Chat Completionsuse_responses_api=Falseopenai/ ids, no codex/ or gpt-5.6

Set up ChatOpenAI for Plan2API

  1. Sign up with a Google account, connect your Claude, ChatGPT, Google AI or Kimi subscription, and copy your p2a_ API key.
  2. Run pip install -U langchain-openai in your Python environment.
  3. Export your key in the shell with export PLAN2API_KEY="p2a_...".
  4. Instantiate ChatOpenAI with base_url="https://api.plan2api.com/v1", api_key set to your key, and use_responses_api=False.
  5. Call invoke, stream or bind_tools on the client just as you would with standard OpenAI models.

If you're in JavaScript, run npm install @langchain/openai @langchain/core and initialize the client with new ChatOpenAI({ model, apiKey, configuration: { baseURL } }). The example below runs Gemini with invoke, streams a response from Claude and asks Kimi for a tool call.

Python
import os

from langchain_core.tools import tool
from langchain_openai import ChatOpenAI


def plan2api(model: str) -> ChatOpenAI:
    return ChatOpenAI(
        model=model,
        base_url="https://api.plan2api.com/v1",
        api_key=os.environ["PLAN2API_KEY"],
        use_responses_api=False,
    )


gemini = plan2api("gemini/gemini-3.8-flash-high")
print(gemini.invoke("Explain vector clocks in two sentences.").content)

claude = plan2api("claude/claude-sonnet-5")
for chunk in claude.stream("Write a haiku about pull requests."):
    print(chunk.content, end="", flush=True)
print()


@tool
def get_weather(city: str) -> str:
    """Return the current weather for a city."""
    return f"Sunny in {city}"


kimi = plan2api("kimi/k3").bind_tools([get_weather])
reply = kimi.invoke("What is the weather in Berlin?")
print(reply.tool_calls)

Gemini in LangChain without a Gemini API key

The native LangChain Gemini integration is ChatGoogleGenerativeAI from the langchain-google-genai package, which needs an API key in GOOGLE_API_KEY (or GEMINI_API_KEY as a fallback) on the Gemini Developer API, or an API key, service account or Application Default Credentials on Vertex AI.

With Plan2API, you use ChatOpenAI and a gemini/ model id to run against your Google AI Pro or Ultra subscription through Antigravity, using the Gemini subscription API instead of a separate Gemini API key. The five 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.

  • All five models, including gemini/gemini-3.8-flash-high, give you the full 1,048,576-token context window.
  • Every gemini/ model accepts text, image, audio and video input.
  • temperature and top_p values are passed straight through to Gemini.
  • JSON mode (json_object and json_schema on response_format) works out of the box.
  • reasoning_effort is supported, and ChatOpenAI sends it as a top-level reasoning_effort field on the request.

Pick a model id

The prefix on the model id selects the provider (gemini/, openai/, kimi/, or claude/ for the Claude subscription API), GET /v1/models lists every id Plan2API serves, including providers you haven't connected (those return HTTP 403 no_credentials), and Codex ids run on your own ChatGPT plan, so pick one your plan includes. The table below lists example model ids, the subscription each one needs and a key note on each.

Plan2API model ids for ChatOpenAI
modelSubscriptionNote
gemini/gemini-4-argon-highGoogle AI Pro or Ultra1,048,576-token context
gemini/gemini-3.8-flash-highGoogle AI Pro or Ultra1,048,576-token context
claude/claude-sonnet-5Claude Pro or MaxNo JSON response_format
claude/claude-opus-5-5Claude Pro or Max1M context, up to 128K output
openai/gpt-6.1-solChatGPT (Codex)Use openai/, not codex/, in JS
kimi/k3Kimi Codetemperature fixed at 1

Keep ChatOpenAI on Chat Completions

Plan2API serves POST /v1/chat/completions and has no /v1/responses endpoint, which matters when ChatOpenAI decides to switch to OpenAI's Responses API on its own.

In Python (langchain-openai 1.7.3), use_responses_api defaults to None, and the client switches to the Responses API by itself if the model name contains codex, if the model starts with gpt-6 and has tools bound, or if you pass options like reasoning, include, truncation or output_version='responses/v1'. Passing use_responses_api=False forces Chat Completions in every case, even on codex/ ids. When you want to control reasoning in Python, pass reasoning_effort='high' rather than a reasoning dict, which would otherwise trigger the Responses API.

In JavaScript (@langchain/openai 1.8.0), useResponsesApi defaults to false, but a model name containing codex or gpt-5.6, or any Responses-only options, will still switch the client over to /v1/responses, so stick to openai/ model ids such as openai/gpt-6.1-sol for your ChatGPT Codex models.

In @langchain/openai, codex/ model ids and any id containing gpt-5.6 ignore useResponsesApi: false and call /v1/responses, so always use the openai/ prefix in JavaScript and skip GPT-5.6 models there.

Streaming, tools and what doesn't work

  • Calling stream() yields token chunks across Gemini, Claude, Codex and Kimi models.
  • When you set a custom base_url, LangChain Python leaves stream_usage off by default, and passing stream_usage=True requests token counts through stream_options (include_usage).
  • bind_tools accepts @tool functions and Pydantic classes on all four providers, returning the model's calls in the message's tool_calls list.
  • with_structured_output defaults to method='json_schema', which sends a response_format that works on Gemini, Codex and Kimi, while Claude models return HTTP 400 unsupported_parameter unless you pass method="function_calling".
  • In Python, ChatOpenAI sends max_tokens over the wire as max_completion_tokens, which the API accepts alongside max_tokens.
  • OpenAIEmbeddings does not work because there is no /v1/embeddings endpoint.
  • The legacy OpenAI text completion class does not work because there is no /v1/completions endpoint.

Troubleshooting LangChain with Plan2API

  • 401 invalid_api_key: PLAN2API_KEY is unset, the key doesn't start with p2a_, or the client sent it in an x-api-key header instead of Authorization: Bearer.
  • 403 no_credentials: your vault has no connected subscription for the provider prefix you requested, so connect an account for that provider in the dashboard.
  • 400 model_not_found: the model string isn't recognized, so check GET /v1/models and pass the full prefixed id.
  • 400 unsupported_parameter: you called with_structured_output with its default json_schema method or set a non-text response_format on a claude/ model, which you fix by setting method="function_calling".
  • Requests hitting /v1/responses: ChatOpenAI switched off Chat Completions, so add use_responses_api=False in Python and replace codex/ prefixes with openai/ and avoid gpt-5.6 ids in JavaScript.
  • 429 daily_requests: you used the Free plan's 50 chat requests for the day (resets at 00:00 UTC), and an agent loop spends one request per model call, so a single tool round trip costs 2; wait for the Retry-After window or move to one of the Pro and Scale plans, which have no daily request cap.

If an error happens after a streaming response has already started, it arrives 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

Can LangChain use Gemini through an OpenAI-compatible API?

Yes, point ChatOpenAI at base_url="https://api.plan2api.com/v1" and pass a gemini/ model id such as gemini/gemini-3.8-flash-high. Add your p2a_ key and use_responses_api=False, and the request runs on your Google AI Pro or Ultra subscription through /v1/chat/completions.

Do I need a Gemini API key for LangChain with Plan2API?

No. Plan2API runs Gemini requests through your connected Google AI Pro or Ultra subscription, whereas ChatGoogleGenerativeAI needs a Gemini API key (GOOGLE_API_KEY or GEMINI_API_KEY) or Vertex AI credentials.

Does Plan2API work with the Responses API in LangChain?

No, it only serves /v1/chat/completions. Pass use_responses_api=False to ChatOpenAI in Python so LangChain doesn't switch endpoints.

How do I get structured output from Claude in LangChain?

Call with_structured_output(Schema, method="function_calling") on your ChatOpenAI instance. The default json_schema method sends a non-text response_format, which Claude models reject with 400 unsupported_parameter.

Does LangChain.js work with Plan2API?

Yes, pass your model, key and base URL to new ChatOpenAI({ model, apiKey, configuration: { baseURL } }). Use openai/ ids instead of codex/ ids, as codex/ names (and any id containing gpt-5.6) force @langchain/openai onto the Responses API.

Can I use OpenAIEmbeddings with Plan2API?

No, Plan2API does not have a /v1/embeddings endpoint, so OpenAIEmbeddings calls fail. Use a separate embeddings provider for vectors and keep ChatOpenAI on Plan2API for chat.

Sources

  1. LangChain ChatOpenAI (Python)docs.langchain.com
  2. LangChain ChatOpenAI (JavaScript)docs.langchain.com
  3. LangChain ChatGoogleGenerativeAIdocs.langchain.com
  4. langchain-openai ChatOpenAI source (GitHub)github.com
  5. langchain-openai 1.7.3 on PyPIpypi.org
  6. LangChain.js ChatOpenAI source (GitHub)github.com
  7. LangChain.js Responses API model routing (GitHub)github.com
  8. langchain-google-genai auth settings (GitHub)github.com