> ## 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.

# API reference

> The Hopscotch API is OpenAI-shaped: one base URL, one bearer key, and the request and response bodies your client already sends.

The Hopscotch API is the product. You point an OpenAI-compatible client at our
base URL, send a Hopscotch API key instead of a provider key, and name the model
you want. Request and response bodies keep the shapes your client already
parses, including error bodies.

## Base URL

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
```

## Authentication

Every route on this API requires a workspace API key in an `Authorization`
header using the Bearer scheme. There is no other way to authenticate a request,
and there are no unauthenticated routes.

Every request to the API carries your key in an `Authorization` header using the
`Bearer` scheme. A missing header, a scheme other than `Bearer`, a key of the
wrong shape, and a key we reject are all answered with `401`.

<CodeGroup>
  ```bash curl theme={"theme":{"light":"vitesse-light","dark":"vesper"}}
  curl https://api.hopscotchlabs.ai/v1/chat/completions \
    -H "Authorization: Bearer $HOPSCOTCH_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "openai/gpt-4o-mini",
      "messages": [{"role": "user", "content": "Say hi in five words."}]
    }'
  ```

  ```python Python theme={"theme":{"light":"vitesse-light","dark":"vesper"}}
  import os
  from openai import OpenAI

  client = OpenAI(
      base_url="https://api.hopscotchlabs.ai/v1",
      api_key=os.environ["HOPSCOTCH_API_KEY"],
  )
  ```

  ```typescript Node theme={"theme":{"light":"vitesse-light","dark":"vesper"}}
  import OpenAI from "openai";

  const client = new OpenAI({
    baseURL: "https://api.hopscotchlabs.ai/v1",
    apiKey: process.env.HOPSCOTCH_API_KEY,
  });
  ```
</CodeGroup>

Keep the key out of your source. Read it from the environment, as above.

Keys are created in the dashboard under Keys. See
[Authentication](/api-reference/authentication) for key format, the 401 you get
for a key we will not accept, and what a key does and does not grant.

## What this API covers

| Route                       | What it does                                                       |
| --------------------------- | ------------------------------------------------------------------ |
| `POST /v1/chat/completions` | Call a model. Streamed or not, depending on `stream` in your body. |
| `POST /v1/responses`        | Call a model in the OpenAI Responses format. Streamed or not.      |
| `GET /v1/models`            | List the models available to call.                                 |
| `GET /v1/models/{id}`       | Read one model's entry.                                            |

Any other path under `/v1` answers `404` with the code
`endpoint_not_supported` in the standard error body, so an endpoint we do not
serve fails the same way every time rather than in a new way per path. A method
we do not serve on a path we do is different: that is a `405` with
`method_not_allowed` and an `Allow` header.

The dashboard has its own private API behind your browser session. It is not an
integration surface, it is not documented here, and it is not covered by
anything on this page.

## Requests

Send `Content-Type: application/json` and a JSON body. The body is forwarded as
you sent it: parameters are not rewritten, dropped, or validated against a
schema of ours, so a parameter your client sends works as soon as the model
behind it supports it.

Model ids are `provider/model`, for example `openai/gpt-4o-mini`. The part before the first slash
names the provider that serves the request, and everything after it is that provider's own id for
the model, passed on as you sent it. A bare id with no provider is refused with `400` and the code
`model_id_not_pinned`. Call `GET /v1/models` for the exact strings you can use.

## Streaming

Set `"stream": true` and the response arrives as server-sent events with
`Content-Type: text/event-stream`, in the same format and with the same
terminating `data: [DONE]` line an OpenAI-compatible client already reads. See
[Streaming](/concepts/streaming) for the full transcript, including the one
extra comment line we add and the events that end a stream early.

## Every response carries a request id

Each request gets an id, returned on two response headers with the same value:
`x-hopscotch-request-id`, which is ours, and `x-request-id`, which is the one the
official OpenAI SDKs surface on their error objects. Error bodies also carry it
as `request_id` inside `error`.

<Note>
  Every response carries the same id on two headers: `x-hopscotch-request-id`,
  which is ours, and `x-request-id`, which is the one the official OpenAI SDKs
  surface on their error objects. Every error envelope repeats it as
  `request_id`. Quote it when you ask us about a request. Without it we are
  guessing at which of your requests you mean.
</Note>

## Errors

Errors use one body shape across the whole API, with a closed set of `type`
values and a stable `code`. Branch on those fields rather than on the message
text. The full contract, including which status carries which code, is in
[Errors](/api-reference/errors).

## Versioning

The `/v1` prefix is part of every path and there is no version header to send.
We add routes, parameters, and response fields; the field set of the error body
is the part we hold still. Treat any field you do not recognise as safe to
ignore, on responses and on the headers documented in
[Headers](/api-reference/headers).
