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

> ## Agent Instructions
> Agents: start with https://docs.pre.dev/agents.md, which has complete recipes, plan access, polling rules, errors and limits.
> Authenticate with the workspace API key (pdk_…) from Integrations → Built-in, sent as Authorization: Bearer <key>.
> REST API: https://api.pre.dev (OpenAPI: https://docs.pre.dev/api-reference/openapi.json). AI Gateway: https://api.pre.dev/v1, OpenAI-compatible (OpenAPI: https://docs.pre.dev/api-reference/ai-gateway.openapi.json).
> pre.dev MCP server: https://api.pre.dev/mcp. Search these docs over MCP at https://docs.pre.dev/mcp.

# Chat completions

> POST /v1/chat/completions, /v1/completions, and /v1/responses in the OpenAI-compatible shape.

`POST https://api.pre.dev/v1/chat/completions` takes the OpenAI-compatible chat completion request body and returns the chat completion response. [`POST /v1/completions`](/ai-gateway/api/completions) (text completions) and [`POST /v1/responses`](/ai-gateway/api/responses) (Responses API shape) work the same way with their own bodies.

<CodeGroup>
  ```bash curl theme={null}
  curl --fail-with-body -i https://api.pre.dev/v1/chat/completions \
    -H "Authorization: Bearer $PREDEV_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek/deepseek-v4.1-flash",
      "messages": [
        { "role": "system", "content": "Answer in one sentence." },
        { "role": "user", "content": "Why is the sky blue?" }
      ]
    }'
  ```

  ```typescript Node.js theme={null}
  import OpenAI from 'openai';

  const client = new OpenAI({ baseURL: 'https://api.pre.dev/v1', apiKey: process.env.PREDEV_API_KEY! });

  const { data: completion, response } = await client.chat.completions
    .create({
      model: 'deepseek/deepseek-v4.1-flash',
      messages: [
        { role: 'system', content: 'Answer in one sentence.' },
        { role: 'user', content: 'Why is the sky blue?' },
      ],
    })
    .withResponse();
  console.log(completion.choices[0].message.content);
  console.log('credits:', response.headers.get('x-predev-credits-charged'));
  ```

  ```python Python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(base_url="https://api.pre.dev/v1", api_key=os.environ["PREDEV_API_KEY"])

  raw = client.chat.completions.with_raw_response.create(
      model="deepseek/deepseek-v4.1-flash",
      messages=[
          {"role": "system", "content": "Answer in one sentence."},
          {"role": "user", "content": "Why is the sky blue?"},
      ],
  )
  completion = raw.parse()
  print(completion.choices[0].message.content)
  print("credits:", raw.headers.get("x-predev-credits-charged"))
  ```
</CodeGroup>

## Request

| Field | Notes |
| - | - |
| `model` | The model id exactly as listed by `GET /v1/models`; append `:online` for web search |
| `messages` | OpenAI chat messages, including image and file content parts |
| `models`, `route`, `transforms` | [Fallbacks and advanced options](/ai-gateway/routing-and-fallbacks) |
| `reasoning`, `reasoning_effort` | Reasoning controls |
| `plugins`, `web_search_options` | Plugins and web search |
| `response_format`, `structured_outputs`, `tools`, `tool_choice`, `parallel_tool_calls` | [Tools and structured output](/ai-gateway/tools-and-structured-output) |
| `prediction`, `verbosity`, `session_id` | Predicted outputs, verbosity, session grouping |
| `stream` | [Streaming](/ai-gateway/streaming); the final chunk carries `usage` |
| `user` | End-user identifier; pre.dev prefixes it with an identifier for your workspace |

Every other standard field (`temperature`, `max_tokens`, `stop`, and so on) works as in the OpenAI API.

## Response

The body is the standard chat completion response. `id` is the pre.dev generation id (`pdg-…`), `model` is the model that answered, and `usage` has the token counts.

```json theme={null}
{
  "id": "pdg-7c1e4b52-9a3d-4f8e-b0c6-2d5a8e913f47",
  "object": "chat.completion",
  "model": "deepseek/deepseek-v4.1-flash",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Sunlight scatters off air molecules, and blue light scatters most." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 21, "completion_tokens": 14, "total_tokens": 35 }
}
```

| Header | Meaning |
| - | - |
| `x-predev-request-id` | `pdr_…`, the gateway's id for this call |
| `x-predev-credits-charged` | Credits charged. Not sent on streamed responses; read [`GET /v1/generation`](/ai-gateway/api/generation) afterwards |
| `x-predev-credits-remaining` | Balance after the call; omitted when the workspace has no credit limit |

Send `x-predev-project-id: <projectId>` to attribute the call to a project. See [usage](/ai-gateway/api/usage).

## Errors

Errors use the OpenAI error shape. Account and billing errors (`401`, `402`, `429`, `503`) add a `predev` object; errors from the model, such as an unknown model id, keep their HTTP status. See [errors](/api-reference/errors#ai-gateway-errors).


## OpenAPI

````yaml api-reference/ai-gateway.openapi.json POST /v1/chat/completions
openapi: 3.1.0
info:
  title: pre.dev AI Gateway API
  version: 1.0.0
  description: >-
    One OpenAI-compatible API for hundreds of models from every major lab, paid
    for in pre.dev credits.


    - **Base URL:** `https://api.pre.dev/v1` for the OpenAI SDKs. The Anthropic
    SDKs take `https://api.pre.dev` and add `/v1/messages` themselves.

    - **Auth:** the workspace API key (`pdk_…`) from Integrations → Built-in in
    the pre.dev dashboard, as `Authorization: Bearer <key>` or `x-api-key`. Keep
    it on a server: it spends the workspace's credits.

    - **Models:** send ids exactly as `GET /v1/models` lists them, such as
    `anthropic/claude-sonnet-5`.

    - **Public directory:** `GET /v1/models/public` lists every model with no
    key and no prices.

    - **Charges:** each call is charged in credits from its metered cost.
    Non-streaming responses report the charge in `x-predev-credits-charged`;
    `GET /v1/generation` reports it for any call. A request is refused with
    `402` before it runs when the balance cannot cover it. Catalog, usage,
    generation and file reads are free.

    - **Limits:** 600 requests per minute per workspace, 30 on the free trial. A
    free workspace can spend 5 credits on AI calls in total, then gets `402
    subscription_required`. Reads other than `GET /v1/files` do not count toward
    the per-minute limit.

    - **Errors:** errors raised by pre.dev use the OpenAI error shape with a
    `predev` object (`GatewayError`). Errors from the model keep their HTTP
    status and message (`ModelError`). Every inference response carries
    `x-predev-request-id`.

    - **Streaming:** `stream: true` returns server-sent events in the native
    format of each endpoint. Lines that start with `:` are keep-alives.


    Example values are illustrative.
  contact:
    name: pre.dev Support
    url: https://pre.dev
    email: support@pre.dev
  license:
    name: Proprietary
    url: https://pre.dev/terms
servers:
  - url: https://api.pre.dev
    description: Production
security:
  - apiKeyAuth: []
  - xApiKey: []
tags:
  - name: Chat
    description: Chat completions, text completions, Responses and Messages.
  - name: Embeddings
    description: Embeddings and rerank.
  - name: Images and video
    description: Image generation and asynchronous video jobs.
  - name: Audio
    description: Speech, music and transcription.
  - name: Files
    description: Documents stored for later chat requests.
  - name: Models
    description: The model catalog, with credit prices.
  - name: Usage
    description: Usage totals and per-call stats.
paths:
  /v1/chat/completions:
    post:
      tags:
        - Chat
      summary: Create a chat completion
      description: >-
        Runs a chat completion in the OpenAI format on any chat model in the
        catalog. Point an OpenAI SDK at `https://api.pre.dev/v1` and pass the
        pre.dev key.


        Standard fields such as `temperature`, `stop`, `seed`, `tools` and
        `response_format` work as in the OpenAI API. A `provider` object is
        removed before the request runs: choose a model, and use `models` for
        fallbacks.


        The playground sends the default example, which does not stream; the
        Streaming example shows `stream: true`. With `stream: true` the response
        is `text/event-stream`. Lines that start with `:` are keep-alive
        comments; ignore them. Credits settle when the stream ends, so streamed
        responses carry `x-predev-request-id` but not the credits headers; `GET
        /v1/generation?id=<id>` reports the charge afterwards. If the client
        disconnects, generation stops shortly after and the call is charged for
        what the model produced.
      operationId: createChatCompletion
      parameters:
        - $ref: '#/components/parameters/ProjectId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
            examples:
              basic:
                summary: One question
                value:
                  model: deepseek/deepseek-v4.1-flash
                  max_tokens: 100
                  stream: false
                  reasoning:
                    enabled: false
                  messages:
                    - role: user
                      content: Say hello in five words.
              streaming:
                summary: Streaming
                value:
                  model: deepseek/deepseek-v4.1-flash
                  max_tokens: 100
                  stream: true
                  reasoning:
                    enabled: false
                  messages:
                    - role: user
                      content: Say hello in five words.
              json_output:
                summary: Structured JSON output
                value:
                  model: deepseek/deepseek-v4.1-flash
                  max_tokens: 200
                  reasoning:
                    enabled: false
                  messages:
                    - role: user
                      content: Name three primary colors.
                  response_format:
                    type: json_schema
                    json_schema:
                      name: colors
                      strict: true
                      schema:
                        type: object
                        properties:
                          colors:
                            type: array
                            items:
                              type: string
                        required:
                          - colors
                        additionalProperties: false
              fallbacks:
                summary: Fallback models
                value:
                  model: deepseek/deepseek-v4.1-flash
                  models:
                    - google/gemini-3.8-flash
                  max_tokens: 100
                  reasoning:
                    enabled: false
                  messages:
                    - role: user
                      content: Say hello in five words.
      responses:
        '200':
          description: >-
            The completion. With `stream: true`, server-sent chunks in the
            OpenAI format ending with `data: [DONE]`.
          headers:
            x-predev-request-id:
              $ref: '#/components/headers/RequestId'
            x-predev-credits-charged:
              $ref: '#/components/headers/CreditsCharged'
            x-predev-credits-remaining:
              $ref: '#/components/headers/CreditsRemaining'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatCompletion'
              example:
                id: pdg-043293a6-d1a8-4695-81fe-603ad4661ebb
                object: chat.completion
                created: 1790500000
                model: deepseek/deepseek-v4.1-flash
                choices:
                  - index: 0
                    message:
                      role: assistant
                      content: Hello there, nice to meet you.
                    finish_reason: stop
                usage:
                  prompt_tokens: 12
                  completion_tokens: 8
                  total_tokens: 20
                system_fingerprint: null
            text/event-stream:
              schema:
                type: string
              example: >
                data:
                {"id":"pdg-043293a6-d1a8-4695-81fe-603ad4661ebb","object":"chat.completion.chunk","created":1790500000,"model":"deepseek/deepseek-v4.1-flash","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"Hello
                there,"},"finish_reason":null}]}


                : processing


                data:
                {"id":"pdg-043293a6-d1a8-4695-81fe-603ad4661ebb","object":"chat.completion.chunk","created":1790500000,"model":"deepseek/deepseek-v4.1-flash","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":"
                nice to meet you."},"finish_reason":"stop"}]}


                data:
                {"id":"pdg-043293a6-d1a8-4695-81fe-603ad4661ebb","object":"chat.completion.chunk","created":1790500000,"model":"deepseek/deepseek-v4.1-flash","system_fingerprint":null,"choices":[],"usage":{"prompt_tokens":12,"completion_tokens":8,"total_tokens":20}}


                data: [DONE]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '404':
          $ref: '#/components/responses/ModelNotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
        '502':
          $ref: '#/components/responses/ModelUnavailable'
        '503':
          $ref: '#/components/responses/BalanceUnavailable'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |-
            curl --fail-with-body https://api.pre.dev/v1/chat/completions \
              -H "Authorization: Bearer $PREDEV_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"model":"deepseek/deepseek-v4.1-flash","max_tokens":100,"stream":false,"reasoning":{"enabled":false},"messages":[{"role":"user","content":"Say hello in five words."}]}'
        - lang: Python
          label: Python (OpenAI SDK)
          source: >-
            import os

            from openai import OpenAI


            client = OpenAI(base_url="https://api.pre.dev/v1",
            api_key=os.environ["PREDEV_API_KEY"])


            completion = client.chat.completions.create(
                model="deepseek/deepseek-v4.1-flash",
                max_tokens=100,
                extra_body={"reasoning": {"enabled": False}},
                messages=[{"role": "user", "content": "Say hello in five words."}],
            )

            print(completion.choices[0].message.content)
        - lang: JavaScript
          label: Node.js (OpenAI SDK)
          source: >-
            import OpenAI from 'openai';


            const client = new OpenAI({ baseURL: 'https://api.pre.dev/v1',
            apiKey: process.env.PREDEV_API_KEY });


            const completion = await client.chat.completions.create({
              model: 'deepseek/deepseek-v4.1-flash',
              max_tokens: 100,
              reasoning: { enabled: false },
              messages: [{ role: 'user', content: 'Say hello in five words.' }],
            });

            console.log(completion.choices[0].message.content);
components:
  parameters:
    ProjectId:
      name: x-predev-project-id
      in: header
      required: false
      schema:
        type: string
      description: >-
        Attribute this call to one of the workspace's projects. An id the
        workspace does not own is ignored.
  schemas:
    ChatCompletionRequest:
      type: object
      required:
        - model
        - messages
      properties:
        model:
          type: string
          description: A model id exactly as listed by `GET /v1/models`.
          example: deepseek/deepseek-v4.1-flash
        models:
          type: array
          items:
            type: string
          description: >-
            Fallback model ids, tried in order when the first choice cannot
            serve the request. The response `model` names the model that
            answered, and the charge follows that model.
        messages:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/ChatMessage'
        stream:
          type: boolean
          default: false
          example: false
          description: >-
            Return server-sent events. The final chunk before `data: [DONE]`
            carries `usage`.
        stream_options:
          type: object
          properties:
            include_usage:
              type: boolean
          description: Optional. pre.dev turns `include_usage` on for every stream.
        max_tokens:
          type: integer
          minimum: 1
          example: 100
          description: >-
            Upper bound on output tokens. Reasoning tokens count toward it, so
            turn reasoning off or allow more when you keep it small.
        max_completion_tokens:
          type: integer
          minimum: 1
        temperature:
          type: number
        top_p:
          type: number
        seed:
          type: integer
        stop:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        tools:
          type: array
          items:
            $ref: '#/components/schemas/Tool'
        tool_choice:
          description: >-
            `auto`, `none`, `required`, or `{ "type": "function", "function": {
            "name": "…" } }`.
          oneOf:
            - type: string
              enum:
                - auto
                - none
                - required
            - type: object
              additionalProperties: true
        parallel_tool_calls:
          type: boolean
        response_format:
          $ref: '#/components/schemas/ResponseFormat'
        reasoning:
          $ref: '#/components/schemas/ReasoningOptions'
        reasoning_effort:
          type: string
          description: Shorthand for `reasoning.effort`.
        modalities:
          type: array
          items:
            type: string
            enum:
              - text
              - image
              - audio
          description: Output modalities, for models that can return images or audio.
        plugins:
          type: array
          items:
            $ref: '#/components/schemas/Plugin'
        session_id:
          type: string
          description: Groups related requests, such as one conversation.
        user:
          type: string
          description: >-
            Your id for the end user. pre.dev prefixes it with a hash of your
            workspace.
      additionalProperties: true
    ChatCompletion:
      type: object
      required:
        - id
        - object
        - model
        - choices
      properties:
        id:
          type: string
          description: Generation id (`pdg-…`). Pass it to `GET /v1/generation`.
        object:
          type: string
          const: chat.completion
        created:
          type: integer
        model:
          type: string
          description: The model that served the call.
        choices:
          type: array
          items:
            type: object
            required:
              - index
              - message
            properties:
              index:
                type: integer
              message:
                type: object
                properties:
                  role:
                    type: string
                    const: assistant
                  content:
                    type:
                      - string
                      - 'null'
                  reasoning:
                    type:
                      - string
                      - 'null'
                    description: Reasoning text, on models that return it.
                  tool_calls:
                    type: array
                    items:
                      $ref: '#/components/schemas/ToolCall'
                additionalProperties: true
              finish_reason:
                type:
                  - string
                  - 'null'
                examples:
                  - stop
                  - length
                  - tool_calls
                  - content_filter
              logprobs:
                type:
                  - object
                  - 'null'
        usage:
          $ref: '#/components/schemas/TokenUsage'
        system_fingerprint:
          type: 'null'
      additionalProperties: true
    ChatMessage:
      type: object
      required:
        - role
      properties:
        role:
          type: string
          enum:
            - system
            - developer
            - user
            - assistant
            - tool
        content:
          description: Text, or an array of content parts for images, files and audio.
          oneOf:
            - type: string
            - type: array
              items:
                $ref: '#/components/schemas/ContentPart'
            - type: 'null'
        name:
          type: string
        tool_calls:
          type: array
          items:
            $ref: '#/components/schemas/ToolCall'
          description: On `assistant` messages that called tools.
        tool_call_id:
          type: string
          description: 'On `tool` messages: the id of the call this message answers.'
      additionalProperties: true
    Tool:
      type: object
      required:
        - type
        - function
      properties:
        type:
          type: string
          const: function
        function:
          type: object
          required:
            - name
          properties:
            name:
              type: string
            description:
              type: string
            parameters:
              type: object
              description: JSON Schema for the arguments.
              additionalProperties: true
            strict:
              type: boolean
    ResponseFormat:
      type: object
      description: >-
        Ask for JSON. `json_schema` enforces a schema on models whose catalog
        row lists `structured_outputs` in `supported_parameters`.
      required:
        - type
      properties:
        type:
          type: string
          enum:
            - text
            - json_object
            - json_schema
        json_schema:
          type: object
          required:
            - name
          properties:
            name:
              type: string
            schema:
              type: object
              additionalProperties: true
            strict:
              type: boolean
    ReasoningOptions:
      type: object
      description: >-
        Reasoning controls for models that support them. Reasoning tokens count
        as output tokens.
      properties:
        effort:
          type: string
          enum:
            - max
            - xhigh
            - high
            - medium
            - low
            - minimal
            - none
        max_tokens:
          type: integer
          description: Token budget for reasoning, on models that accept one.
        exclude:
          type: boolean
          description: Reason without returning the reasoning text.
        enabled:
          type: boolean
      additionalProperties: true
    Plugin:
      type: object
      description: >-
        An extra capability for this call: `web` adds web search results,
        `file-parser` reads PDFs for models without native document input,
        `response-healing` repairs malformed JSON output, and
        `context-compression` shortens prompts that exceed the context window.
      required:
        - id
      properties:
        id:
          type: string
          examples:
            - web
            - file-parser
            - response-healing
            - context-compression
      additionalProperties: true
    ToolCall:
      type: object
      required:
        - id
        - type
        - function
      properties:
        id:
          type: string
        type:
          type: string
          const: function
        function:
          type: object
          required:
            - name
            - arguments
          properties:
            name:
              type: string
            arguments:
              type: string
              description: JSON-encoded arguments.
    TokenUsage:
      type: object
      description: >-
        Token counts for the call. Charges are reported in credits by the
        `x-predev-credits-charged` header and `GET /v1/generation`.
      required:
        - prompt_tokens
        - completion_tokens
        - total_tokens
      properties:
        prompt_tokens:
          type: integer
        completion_tokens:
          type: integer
        total_tokens:
          type: integer
        prompt_tokens_details:
          type:
            - object
            - 'null'
          properties:
            cached_tokens:
              type: integer
          additionalProperties: true
        completion_tokens_details:
          type:
            - object
            - 'null'
          properties:
            reasoning_tokens:
              type: integer
          additionalProperties: true
      additionalProperties: true
    InvalidJsonBody:
      type: object
      description: The request body is not valid JSON. Checked before authentication.
      required:
        - error
      properties:
        error:
          type: string
          const: Invalid JSON body
    ModelError:
      type: object
      description: >-
        An error returned by the model for this request. The HTTP status is the
        model's own; `code` usually repeats it.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
          properties:
            message:
              type: string
            code:
              type:
                - integer
                - string
            metadata:
              type: object
              properties:
                raw:
                  type: string
                  description: The model's own error text, when it adds detail.
                reasons:
                  type: array
                  items:
                    type: string
                  description: Moderation categories when the input was flagged.
                flagged_input:
                  type: string
                  description: The part of the input that was flagged.
    GatewayError:
      type: object
      description: >-
        An error raised by pre.dev, in the OpenAI error shape with an extra
        `predev` object (absent on `catalog_unavailable` from the catalog
        listings). Branch on `error.code`.
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
            - type
            - code
            - param
          properties:
            message:
              type: string
              description: What went wrong and what to do next.
            type:
              type: string
              enum:
                - authentication_error
                - insufficient_credits
                - subscription_required
                - invalid_request_error
                - not_found_error
                - rate_limit_error
                - server_error
              description: >-
                Error class. The OpenAI and Anthropic SDKs map the HTTP status
                to their own exception types.
            code:
              type: string
              enum:
                - missing_api_key
                - invalid_api_key
                - too_many_auth_failures
                - insufficient_credits
                - subscription_required
                - rate_limit_exceeded
                - balance_unavailable
                - invalid_request
                - missing_id
                - not_found
                - not_ready
                - upstream_unavailable
                - catalog_unavailable
                - internal_error
              description: >-
                | Code | HTTP | Meaning |

                | --- | --- | --- |

                | `missing_api_key` | 401 | No `Authorization: Bearer` or
                `x-api-key` header. |

                | `invalid_api_key` | 401 | The key is unknown, or was rotated
                more than 15 minutes ago. |

                | `too_many_auth_failures` | 429 | More than 30 failed key
                attempts from this IP address in a minute. |

                | `insufficient_credits` | 402 | The balance is zero or below
                the estimate for this request. Nothing ran. |

                | `subscription_required` | 402 | A free workspace used its 5
                credits of AI calls. |

                | `rate_limit_exceeded` | 429 | Over the per-minute request
                limit for the workspace. |

                | `balance_unavailable` | 503 | The balance could not be read.
                Nothing ran. |

                | `invalid_request` | 400 | `/v1/audio/speech` is missing
                `model` or `input`, or the model does not produce audio. |

                | `missing_id` | 400 | `/v1/generation` was called without `id`.
                |

                | `not_found` | 404 | Unknown path, or a file, video job,
                response or generation that belongs to another workspace,
                including one a request refers to. On `/v1/generation`, also a
                call that recorded no stats (a failed call, for example) or a
                streamed call that is still running. |

                | `not_ready` | 404 or 502 | `/v1/generation` found the call,
                but its stats are not available yet (404) or could not be read
                (502). |

                | `upstream_unavailable` | 502 | The model did not answer, or
                returned no audio. |

                | `catalog_unavailable` | 502 or 503 | The model catalog could
                not be read: 502 from the catalog listings, 503 from `GET
                /v1/models/public`. Retry shortly. |

                | `internal_error` | 500 | Unexpected error. |
            param:
              type: 'null'
            predev:
              $ref: '#/components/schemas/GatewayErrorDetails'
    ContentPart:
      type: object
      description: >-
        One part of a message. Common types: `text`, `image_url` (an https or
        base64 data URL), `file` (a URL, a base64 data URL, or a `file_id` from
        `POST /v1/files`), and `input_audio` (base64 audio with its format).
      required:
        - type
      properties:
        type:
          type: string
          examples:
            - text
            - image_url
            - file
            - input_audio
        text:
          type: string
        image_url:
          type: object
          required:
            - url
          properties:
            url:
              type: string
            detail:
              type: string
              enum:
                - auto
                - low
                - high
        file:
          type: object
          properties:
            filename:
              type: string
            file_data:
              type: string
              description: A URL or a base64 data URL.
            file_id:
              type: string
              description: An id returned by `POST /v1/files`.
        input_audio:
          type: object
          required:
            - data
            - format
          properties:
            data:
              type: string
              description: Base64-encoded audio.
            format:
              type: string
              examples:
                - wav
                - mp3
      additionalProperties: true
    GatewayErrorDetails:
      type: object
      description: Extra fields for some error codes; an empty object for the rest.
      properties:
        credits_remaining:
          type: number
          description: >-
            Workspace balance. Sent with `insufficient_credits` and
            `subscription_required`.
        estimated_credits:
          type: number
          description: >-
            Estimated credits the request needs. Sent with
            `insufficient_credits`.
        trial_credits_used:
          type: number
          description: >-
            Credits the free trial has spent on AI calls. Sent with
            `subscription_required`.
        topup_url:
          type: string
          format: uri
          description: Where to add credits or subscribe.
        retry_after:
          type: integer
          description: Seconds to wait. Also sent as the `Retry-After` header.
        available_models:
          type: array
          items:
            type: string
          description: >-
            Speech and music model ids. Sent with `invalid_request` from
            `/v1/audio/speech`.
  headers:
    RequestId:
      description: >-
        pre.dev id for this request (`pdr_…`). Quote it when you contact
        support.
      schema:
        type: string
        example: pdr_043293a6-d1a8-4695-81fe-603ad4661ebb
    CreditsCharged:
      description: >-
        Credits charged for this call. Streamed responses do not carry it
        because the charge settles after the stream ends; read `GET
        /v1/generation` for those.
      schema:
        type: number
        example: 0.005
    CreditsRemaining:
      description: >-
        Workspace credit balance after this call. Omitted on plans without a
        credit limit.
      schema:
        type: number
        example: 412.5
    RetryAfter:
      description: Seconds to wait before retrying.
      schema:
        type: integer
        example: 12
  responses:
    BadRequest:
      description: >-
        The body is not valid JSON (checked before authentication), or the model
        rejected the request, for example an unknown model id. Errors from the
        model keep their status and use the `ModelError` shape.
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/InvalidJsonBody'
              - $ref: '#/components/schemas/ModelError'
          examples:
            invalid_json:
              summary: Body is not valid JSON
              value:
                error: Invalid JSON body
            unknown_model:
              summary: Unknown model id
              value:
                error:
                  message: nope/not-a-model is not a valid model ID
                  code: 400
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          examples:
            missing_api_key:
              summary: No key sent
              value:
                error:
                  message: >-
                    Send your pre.dev API key as `Authorization: Bearer <key>`
                    or `x-api-key`. Copy it from Integrations → Built-in:
                    https://pre.dev/projects/integrations
                  type: authentication_error
                  code: missing_api_key
                  param: null
                  predev: {}
            invalid_api_key:
              summary: Unknown or retired key
              value:
                error:
                  message: Invalid API key
                  type: authentication_error
                  code: invalid_api_key
                  param: null
                  predev: {}
    PaymentRequired:
      description: >-
        The workspace cannot pay for this request. Nothing was sent to the model
        and nothing was charged.
      headers:
        x-predev-credits-remaining:
          $ref: '#/components/headers/CreditsRemaining'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          examples:
            no_credits:
              summary: Balance is zero
              value:
                error:
                  message: >-
                    This pre.dev workspace has no credits left for AI calls. Top
                    up at https://pre.dev/billing or enable auto-recharge.
                  type: insufficient_credits
                  code: insufficient_credits
                  param: null
                  predev:
                    credits_remaining: 0
                    estimated_credits: 0.05
                    topup_url: https://pre.dev/billing
            below_estimate:
              summary: Balance is below the estimate
              value:
                error:
                  message: >-
                    This request needs about 10.00 credits and the workspace has
                    3.20 left. Top up at https://pre.dev/billing.
                  type: insufficient_credits
                  code: insufficient_credits
                  param: null
                  predev:
                    credits_remaining: 3.2
                    estimated_credits: 10
                    topup_url: https://pre.dev/billing
            trial_used:
              summary: Free trial allowance used
              value:
                error:
                  message: >-
                    The free trial includes 5 credits of AI calls and this
                    workspace has used them. Subscribe at
                    https://pre.dev/billing to keep going.
                  type: subscription_required
                  code: subscription_required
                  param: null
                  predev:
                    credits_remaining: 14.2
                    trial_credits_used: 5.0132
                    topup_url: https://pre.dev/billing
    ModelNotFound:
      description: >-
        The request refers to a file, response or video job that is not this
        workspace's (`not_found` from pre.dev; nothing ran and nothing was
        charged), or the model could not serve the request (its own status and
        message, in the `ModelError` shape).
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/GatewayError'
              - $ref: '#/components/schemas/ModelError'
          examples:
            foreign_reference:
              summary: A file that is not this workspace's
              value:
                error:
                  message: No file with id file-2Lm9Rt belongs to this workspace.
                  type: not_found_error
                  code: not_found
                  param: null
                  predev: {}
            model_not_found:
              summary: The model cannot serve the request
              value:
                error:
                  message: No endpoints found matching your data policy.
                  code: 404
    RateLimited:
      description: >-
        Too many requests. Wait `Retry-After` seconds when it is present. A
        `rate_limit_exceeded` refusal is per workspace per minute (600, or 30 on
        the free trial). An error from the model keeps the `ModelError` shape.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/GatewayError'
              - $ref: '#/components/schemas/ModelError'
          examples:
            rate_limit_exceeded:
              summary: Workspace rate limit
              value:
                error:
                  message: >-
                    Rate limit of 600 requests per minute exceeded for this
                    workspace.
                  type: rate_limit_error
                  code: rate_limit_exceeded
                  param: null
                  predev:
                    retry_after: 12
            too_many_auth_failures:
              summary: Failed key attempts from this IP
              value:
                error:
                  message: >-
                    Too many failed API key attempts from this address. Try
                    again in a minute.
                  type: rate_limit_error
                  code: too_many_auth_failures
                  param: null
                  predev:
                    retry_after: 60
            model_rate_limited:
              summary: The model is rate-limited
              value:
                error:
                  message: The model returned an error
                  code: 429
                  metadata:
                    raw: deepseek/deepseek-v4.1-flash is temporarily rate-limited.
    ServerError:
      description: Unexpected error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          example:
            error:
              message: The pre.dev AI gateway hit an unexpected error.
              type: server_error
              code: internal_error
              param: null
              predev: {}
    ModelUnavailable:
      description: >-
        The model did not answer. Retry with backoff, or send `models`
        fallbacks.
      content:
        application/json:
          schema:
            anyOf:
              - $ref: '#/components/schemas/GatewayError'
              - $ref: '#/components/schemas/ModelError'
          examples:
            upstream_unavailable:
              summary: No answer from the model
              value:
                error:
                  message: 'The model provider did not answer: timed out'
                  type: server_error
                  code: upstream_unavailable
                  param: null
                  predev: {}
            model_error:
              summary: The model returned a non-JSON error
              value:
                error:
                  message: The model provider returned an error (HTTP 502)
                  code: 502
    BalanceUnavailable:
      description: >-
        The credit balance could not be read, so nothing ran. Retry after
        `Retry-After` seconds.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          example:
            error:
              message: Could not read this workspace's credit balance. Retry shortly.
              type: server_error
              code: balance_unavailable
              param: null
              predev:
                retry_after: 5
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: pdk_ API key
      description: >-
        The workspace API key (`pdk_…`) from Integrations → Built-in in the
        pre.dev dashboard.
    xApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Alternative to `Authorization: Bearer`. The Anthropic SDKs send this
        header.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.