> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hopscotchlabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Framework integrations

> Why every OpenAI-compatible framework works here, the one change that is not optional, and which page covers your framework.

export const FeatureStatus = ({missing, feature, instead, detail, children}) => <Info>
    <strong>Not available yet: {missing ?? feature}.</strong>
    {instead ?? detail ? ` ${instead ?? detail}` : null} This page documents what
    the product does today. When that changes, this page changes with it.
    {children}
  </Info>;

export const NotDocumented = ({subject, reason}) => <Info>
    <strong>{subject} is not documented here.</strong> {reason} We would rather
    say nothing than describe something you cannot use.
  </Info>;

Every framework in this section works here for the same reason, and it is worth
saying once rather than seven times: each of them already has an
OpenAI-compatible provider, because each of them already talks to OpenAI. Point
that provider at our base URL, give it a Hopscotch key, and the framework does not
need to know anything else has changed.

Point your existing OpenAI client at `https://api.hopscotchlabs.ai` and give it a
Hopscotch API key. Nothing else about your code changes.

```text Base URL theme={"theme":{"light":"vitesse-light","dark":"vesper"}}
https://api.hopscotchlabs.ai
```

## The one change that is not optional

**Every model id names its provider.** `gpt-4o-mini` is not a model id here;
`openai/gpt-4o-mini` is. A bare id is refused with `400` and the code
`model_id_not_pinned`. The refusal names the forms it accepts and points you at
`GET /v1/models` for the exact strings your key can call. It arrives as
`invalid_request_error` with `param` set to `model`, in the ordinary error
envelope, so your existing error handling parses it.

This is the change that breaks an otherwise untouched application, and it breaks
loudly rather than quietly. It matters more in a framework than in a bare SDK,
for a reason worth knowing before you debug it: **some frameworks carry a default
model of their own**, so a framework you never told which model to use is still
sending one, and the name it sends is a bare OpenAI id. The page for your
framework says whether yours does. [Models](/concepts/models) covers the id
forms and [Migrate from OpenAI](/resources/migrate-from-openai) covers the rest
of the move.

## The surface a framework can reach

The documented API is `POST /v1/chat/completions` plus the catalog reads,
`GET /v1/models` and `GET /v1/models/{id}`. That is what these pages configure
and it is the whole of what they claim.

Two consequences reach frameworks specifically, and each page says which of them
applies to it:

* **A framework whose default path is not chat completions has to be pinned to
  chat completions.** Two of the libraries here now reach for OpenAI's newer
  Responses API when you do not say otherwise. Chat completions is the surface
  this site documents, so these pages pin it explicitly rather than leaving the
  choice to a library default that moved once and may move again.
* **Embeddings have no home here.** A framework that reaches for embeddings to
  build an index, a retriever, or a memory will not get them from this API, and
  the failure arrives when that code path first runs rather than at
  configuration time. Where a framework does this by default, its page says so
  and says what to set instead.

See [OpenAI compatibility](/get-started/openai-compatibility) for the endpoint
table and the refusals.

## What every one of these pages assumes

* **The base URL carries `/v1` and nothing after it.** Every library here builds
  its request path by appending `/chat/completions` to what you configure, so
  `https://api.hopscotchlabs.ai/v1` is the value and `https://api.hopscotchlabs.ai` is not.
  Getting this wrong produces a `404` rather than a helpful message.
* **The key comes from the environment.** Every example reads it from a variable
  rather than holding it in source. A Hopscotch key spends real credit.
* **Nothing Hopscotch-specific goes in the request.** Only `Authorization` and
  `Content-Type` are read, and `x-hopscotch-*` is stripped inbound, so a
  framework's custom-header option cannot change how a request is served.

## The pages

<CardGroup cols={2}>
  <Card title="OpenAI SDK for Python" icon="brand-python" href="/integrations/openai-sdk-python">
    The reference case. Two constructor arguments.
  </Card>

  <Card title="OpenAI SDK for Node" icon="brand-nodejs" href="/integrations/openai-sdk-node">
    The same two, plus the one browser setting to leave alone.
  </Card>

  <Card title="Vercel AI SDK" icon="triangle" href="/integrations/vercel-ai-sdk">
    Which of its two OpenAI providers to use, and why the default call shape is the wrong one here.
  </Card>

  <Card title="LangChain" icon="link" href="/integrations/langchain">
    Python and JavaScript. The default model is the thing that bites.
  </Card>

  <Card title="LlamaIndex" icon="stack-2" href="/integrations/llamaindex">
    Why the plain OpenAI class rejects our ids before a request is sent.
  </Card>

  <Card title="Pydantic AI" icon="shield-check" href="/integrations/pydantic-ai">
    The base URL goes on the provider, not the model.
  </Card>
</CardGroup>

## What we did not verify

**Checked, and how.** That each framework exposes a base-URL setting, what that
setting is called, what type it takes, and which object it belongs to. Each page
names the library documentation or source file the setting was read from, and the
gotcha on each page was read the same way. These are facts about public
libraries and you can check them where we did.

**Not checked.** That a call configured this way succeeds against our hostname.
No example in this section has been executed end to end, against production or
anywhere else, and DOCS\_PLAN's runnability rule is the reason each page says so
rather than implying otherwise by staying silent. What is missing is not effort:
the base URL this site prints is not yet a host that answers, so there is
nothing these examples could have been run against. When that lands, these pages
get a transcript and this callout changes.

**Also not checked.** Library version behaviour over time. Every fact here was
read from a current version of a library we do not control, and any of them can
change it. Where a library has already changed one of these settings once, the
page says which version the fact belongs to.
