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

# Create a text completion

> Send an OpenAI text completion request, the older format that takes a `prompt` rather than `messages`. Set `stream: true` for server-sent events.

The body is forwarded as you sent it, so a field this page does not name still reaches the provider, and the reply is the provider's text completion object.

On the platform's own provider keys this route applies the same refusals as chat completions. See the 400 response. A request served on your own provider key keeps every one of those fields.

Credit is held when the request is admitted and settled against the provider's own token counts when it finishes. You are charged the provider's rate at face value. Nothing is added per request.

To read back the tokens and charge of one request afterwards, send the value of the `x-hopscotch-request-id` response header to `GET /v1/usage/{id}`.



## OpenAPI

````yaml /api-reference/openapi.public.json post /v1/completions
openapi: 3.0.3
info:
  title: Hopscotch
  version: v1
  description: >-
    An OpenAI-compatible inference API. Point an OpenAI client at
    https://api.hopscotchlabs.ai, give it a Hopscotch API key, and call models
    across providers on one prepaid balance.


    Every response, errors included, matches the shape an unmodified OpenAI SDK
    expects.
servers:
  - url: https://api.hopscotchlabs.ai
    description: Production
security:
  - customerApiKey: []
tags:
  - name: Chat
    description: Chat completions, streamed or not.
  - name: Models
    description: What you can call.
  - name: Completions
    description: Text completions, streamed or not.
  - name: Messages
    description: The Anthropic Messages API, streamed or not.
  - name: Usage
    description: What one request recorded and what it cost.
paths:
  /v1/completions:
    post:
      tags:
        - Completions
      summary: Create a text completion
      description: >-
        Send an OpenAI text completion request, the older format that takes a
        `prompt` rather than `messages`. Set `stream: true` for server-sent
        events.


        The body is forwarded as you sent it, so a field this page does not name
        still reaches the provider, and the reply is the provider's text
        completion object.


        On the platform's own provider keys this route applies the same refusals
        as chat completions. See the 400 response. A request served on your own
        provider key keeps every one of those fields.


        Credit is held when the request is admitted and settled against the
        provider's own token counts when it finishes. You are charged the
        provider's rate at face value. Nothing is added per request.


        To read back the tokens and charge of one request afterwards, send the
        value of the `x-hopscotch-request-id` response header to `GET
        /v1/usage/{id}`.
      operationId: createCompletion
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                model:
                  type: string
                  description: >-
                    A model id in `provider/model` form, or
                    `profile/{identifier}` for one of your workspace's routing
                    profiles. A bare model id is refused with 400 and the code
                    `model_id_not_pinned`. The catalog must list the model for
                    completions. List what you can call with GET /v1/models.
                  example: openai/gpt-4o-mini
                prompt:
                  description: >-
                    What to complete: a string, an array of strings, an array of
                    token ids, or an array of token id arrays.
                  oneOf:
                    - type: string
                      nullable: true
                    - type: array
                      items:
                        type: string
                    - type: array
                      items:
                        type: integer
                    - type: array
                      items:
                        type: array
                        items:
                          type: integer
                stream:
                  type: boolean
                  description: >-
                    Return the reply as server-sent events instead of one JSON
                    body.
                  default: false
                max_tokens:
                  type: integer
                  minimum: 1
                  description: >-
                    The most output tokens you will accept. Sending it also
                    lowers the credit held for the request while it runs. Omit
                    it and the model's published maximum output is held instead.
              required:
                - model
                - prompt
              additionalProperties: true
              description: >-
                An OpenAI text completion request. Fields beyond the ones named
                here are forwarded to the provider unchanged rather than refused
                for being unfamiliar.
            example:
              model: openai/gpt-4o-mini
              prompt: Say hi in five words.
      responses:
        '200':
          description: >-
            The completion, in OpenAI's text completion format as the provider
            produced it. A response that is not streamed carries the provider's
            token counts in its own `usage` object.


            When `stream` is true the body is `text/event-stream` instead, in
            OpenAI's own chunk format, ending with `data: [DONE]`.
          headers:
            x-hopscotch-served-by:
              $ref: '#/components/headers/ServedBy'
              description: >-
                The full id, "{provider}/{model}", of the model that actually
                answered: the pinned id when the request named one directly, or
                the routing-profile chain member that served when the request
                named a profile.
              schema:
                type: string
                example: openai/gpt-4o-mini
            x-hopscotch-served-via:
              $ref: '#/components/headers/ServedVia'
              description: >-
                Present, with the value `backup`, when a backup route served
                this request. Absent on every other response, and never sent
                with any other value, so a client that has never read it sees
                nothing change about an ordinary request. The provider named on
                x-hopscotch-provider and in the body is still the one you asked
                for.
              schema:
                type: string
                enum:
                  - backup
                example: backup
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
            x-request-id:
              $ref: '#/components/headers/SdkRequestId'
            x-hopscotch-provider:
              $ref: '#/components/headers/Provider'
            x-hopscotch-retry-attempt-count:
              $ref: '#/components/headers/RetryAttemptCount'
            x-hopscotch-cache-status:
              $ref: '#/components/headers/CacheStatus'
            x-hopscotch-trace-id:
              $ref: '#/components/headers/TraceId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TextCompletion'
              example:
                id: cmpl-EXAMPLE
                object: text_completion
                created: 1756080000
                model: openai/gpt-4o-mini
                choices:
                  - text: Hello, good to meet you.
                    index: 0
                    logprobs: null
                    finish_reason: stop
                usage:
                  prompt_tokens: 6
                  completion_tokens: 7
                  total_tokens: 13
        '400':
          description: >-
            The request cannot be served as sent. `code` is null for a missing
            parameter, with `param` naming it, `model_id_not_pinned` for a model
            id that names no provider, and `provider_key_refused` when the
            request ran on your own key for a provider that rejected it or
            refused this particular call under it. A refusal the provider made
            about this request is relayed with the provider's own status and its
            own sentence, quoted after the provider's name.


            On the platform's own provider keys this route also refuses, with
            `code` null and `param` naming the field and never its value, a
            field that buys something this platform cannot bill yet or keeps the
            conversation at the provider: `store: true`, a `service_tier` other
            than `auto`, `default` or `on_demand`, a hosted tool the provider
            charges for per call, audio in or out, and the other fields this
            platform does not meter.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_model:
                  summary: No model named
                  value:
                    error:
                      message: >-
                        You must provide a model parameter naming the model to
                        call. It is read to work out what the request could cost
                        before it is sent.
                      type: invalid_request_error
                      param: model
                      code: null
                      request_id: REQUEST_ID
                model_id_not_pinned:
                  summary: The model id does not name its provider
                  value:
                    error:
                      message: >-
                        The model "gpt-4o-mini" does not name its provider. A
                        model field carries either "provider/model", where the
                        part before the first slash is a provider this platform
                        serves and the rest is that provider's own id for the
                        model, for example "anthropic/claude-opus-4-5", or
                        "profile/{identifier}", one of your workspace's routing
                        profiles, for example "profile/fast". GET /v1/models
                        lists the exact strings this key can call.
                      type: invalid_request_error
                      param: model
                      code: model_id_not_pinned
                      request_id: REQUEST_ID
                store_true:
                  summary: Asked the platform to store the conversation
                  value:
                    error:
                      message: >-
                        "store" asks the provider to keep or reuse a stored
                        conversation, and this platform stores none. Remove it,
                        or send the request on your own provider key.
                      type: invalid_request_error
                      param: store
                      code: null
                      request_id: REQUEST_ID
                provider_key_refused:
                  summary: Your own provider key was rejected
                  value:
                    error:
                      message: >-
                        openai rejected your workspace's own openai key (401),
                        so the credential itself was not accepted. Replace it on
                        the Provider keys screen. While your workspace holds a
                        key for openai, every request to openai runs on yours
                        and none is sent on a Hopscotch key, so no other
                        credential was tried for it. Nothing was charged for
                        this request. Remove the key on the Provider keys screen
                        and these requests go back to running on Hopscotch's key
                        and being charged for.
                      type: invalid_request_error
                      param: null
                      code: provider_key_refused
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '401':
          description: >-
            No key, a scheme other than Bearer, a key of the wrong shape, or a
            key we reject. An unknown key and a revoked key are answered with
            one identical message on purpose.


            A key past its own expiry date is refused here too, with code
            `key_expired` and a message naming the date. It is checked before
            the per-minute rate limiter, so an expired key never consumes that
            allowance. Expired keys are not renewed: create a new one.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: Incorrect API key provided.
                  type: authentication_error
                  param: null
                  code: invalid_api_key
                  request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '402':
          description: >-
            The request will not be paid for, and nothing was charged. Code
            `insufficient_credit` is the workspace being out of credit, which
            stops every key on it. Code `key_limit_exceeded` is the sending key
            reaching its own credit limit, which leaves every other key in the
            workspace serving normally; it is refused before any credit is held,
            and the message names what that key has settled and holds inside its
            current window.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                insufficient_credit:
                  summary: The workspace is out of credit
                  value:
                    error:
                      message: >-
                        This account has 54 minor units available and the
                        request needs 55 held.
                      type: insufficient_quota
                      param: null
                      code: insufficient_credit
                      request_id: REQUEST_ID
                key_limit_exceeded:
                  summary: This key is at its own limit
                  value:
                    error:
                      message: >-
                        This key may spend $20.00 in its current window and has
                        $18.40 settled and $1.70 held against that, so a request
                        needing $0.30 more is refused. Nothing was charged for
                        it and no credit was held. The limit belongs to this key
                        alone, so other keys in the workspace are unaffected.
                        This limit resets monthly on UTC calendar windows, so
                        requests are admitted again when the window rolls. It
                        can also be raised or removed on the Keys screen.
                      type: insufficient_quota
                      param: null
                      code: key_limit_exceeded
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '403':
          description: >-
            Refused for a setting the caller owns rather than anything about the
            model, and `code` names which. A key whose account staff have
            suspended is refused with code `account_suspended`, before any
            credit is held or any provider is called; contact support, because
            retrying will not change the answer.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                account_suspended:
                  summary: The key's account is suspended
                  value:
                    error:
                      message: >-
                        This account is suspended, so it cannot send requests.
                        Contact support. Request id REQUEST_ID.
                      type: permission_error
                      param: null
                      code: account_suspended
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '404':
          description: >-
            The model cannot be served, and the two cases are told apart by
            `code`. `model_not_found` means the id is in no catalog at all,
            which is what a typo produces, so check the spelling or list what
            this key can call with `GET /v1/models`. `model_not_available` means
            the id is catalogued and is not being served right now, or that the
            catalog does not list it for this endpoint. In the second case the
            message names the endpoint families the catalog does list it for, so
            move to a model that is listed for this one. No provider was called
            either way.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                model_not_found:
                  summary: No model of that id exists
                  value:
                    error:
                      message: >-
                        The model "MODEL_ID" does not exist. Check the spelling,
                        or list the models this key can call with GET
                        /v1/models.
                      type: not_found_error
                      param: null
                      code: model_not_found
                      request_id: REQUEST_ID
                model_not_available:
                  summary: Known to us, and not being served right now
                  value:
                    error:
                      message: >-
                        The model "MODEL_ID" is not currently available. It is
                        known to this platform and is not being served right
                        now, so retrying later is worth more than changing the
                        request.
                      type: not_found_error
                      param: null
                      code: model_not_available
                      request_id: REQUEST_ID
                model_not_available_endpoint:
                  summary: Live, and not offered on this endpoint
                  value:
                    error:
                      message: >-
                        "MODEL_ID" is not offered on this endpoint: the catalog
                        lists it for chat_completions and not for completions.
                      type: not_found_error
                      param: null
                      code: model_not_available
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '413':
          description: >-
            The request body is larger than the 8388608 byte maximum this API
            accepts, so it was refused at the door. A body that declares its
            length is refused without a byte being read; one that declares none
            is read only as far as the ceiling and then abandoned. Nothing was
            parsed, no credit was held, no model was called and nothing was
            charged.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                payload_too_large:
                  summary: The request body is over the ceiling
                  value:
                    error:
                      message: >-
                        This request body is larger than the 8388608 byte
                        maximum this API accepts. Nothing was read, no model was
                        called and nothing was charged. Send fewer messages, a
                        shorter prompt, or fewer inputs.
                      type: invalid_request_error
                      param: null
                      code: payload_too_large
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '429':
          description: >-
            A limit refused the request. `rate_limit_exceeded` is this key's own
            request rate and carries `Retry-After`. `spend_rate_exceeded` is the
            account spend rate cap, which counts the credit held for requests
            rather than the credit they settle at; send `max_tokens` to hold
            less. `provider_key_refused` is your own key for a provider being
            over its limit there; it clears on its own and carries no
            `Retry-After`. `upstream_rate_limited` is the model's provider
            rate-limiting the call: nothing about the request is wrong, nothing
            is charged, and it carries `Retry-After`.
          headers:
            Retry-After:
              schema:
                type: integer
                minimum: 1
              description: >-
                Seconds to wait. Present on `rate_limit_exceeded` and on
                `upstream_rate_limited`.
              example: 17
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                rate_limit_exceeded:
                  summary: This key's request rate
                  value:
                    error:
                      message: >-
                        Rate limit reached for this key. Try again in 12
                        seconds. Request id REQUEST_ID.
                      type: rate_limit_error
                      param: null
                      code: rate_limit_exceeded
                      request_id: REQUEST_ID
                spend_rate_exceeded:
                  summary: The account spend rate cap
                  value:
                    error:
                      message: >-
                        This account has already reserved 5000 minor units in
                        the last 60 seconds, which is at its ceiling of 5000.
                        Requests are admitted again within 60 seconds of the
                        earliest reservation counted, with nothing to do in the
                        meantime.
                      type: rate_limit_error
                      param: null
                      code: spend_rate_exceeded
                      request_id: REQUEST_ID
                provider_key_refused:
                  summary: Your own provider key is over its limit
                  value:
                    error:
                      message: >-
                        openai refused this request as over its limits, on your
                        workspace's own openai key. This is your account's limit
                        at openai rather than ours. While your workspace holds a
                        key for openai, every request to openai runs on yours
                        and none is sent on a Hopscotch key, so no other
                        credential was tried for it. Nothing was charged for
                        this request. Remove the key on the Provider keys screen
                        and these requests go back to running on Hopscotch's key
                        and being charged for.
                      type: rate_limit_error
                      param: null
                      code: provider_key_refused
                      request_id: REQUEST_ID
                upstream_rate_limited:
                  summary: The model's provider rate-limited the call
                  value:
                    error:
                      message: >-
                        The provider serving this model is rate-limiting
                        requests right now. Nothing was charged. Retry after the
                        number of seconds in the Retry-After header. Quote the
                        request id if you contact support.
                      type: rate_limit_error
                      param: null
                      code: upstream_rate_limited
                      request_id: REQUEST_ID
        '500':
          description: A fault on our side. The request id is the one thing worth keeping.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: >-
                    The server had an error while processing your request. Sorry
                    about that! Quote the request id if you contact support.
                  type: api_error
                  param: null
                  code: null
                  request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '503':
          description: >-
            Ours rather than yours, and `code` names the condition.
            `paused_by_owner` clears only when somebody lifts the pause, so
            retrying on a timer will not help. `balance_unavailable` (we could
            not read the balance, so the request was refused rather than served
            unmetered), `model_not_priceable` and `model_pricing_unreadable` (a
            model we list could not be priced for this call) and
            `no_provider_configured` (we are not currently configured to serve
            this) all clear without you doing anything.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                paused_by_owner:
                  summary: Somebody pressed Pause
                  value:
                    error:
                      message: >-
                        Every request on this account is paused, because
                        somebody with access to it pressed Pause in the
                        dashboard. Nothing was charged for this request and no
                        credit was held for it. It is retryable, and it will be
                        refused the same way until the pause is lifted, so
                        retrying on a timer will not clear it. Requests start
                        working again the moment the pause is lifted from the
                        same control, with nothing else to do and nothing to
                        re-create.
                      type: server_error
                      param: null
                      code: paused_by_owner
                      request_id: REQUEST_ID
                balance_unavailable:
                  summary: We could not read the balance
                  value:
                    error:
                      message: >-
                        Your credit balance could not be checked while this
                        request was running, so it was stopped rather than left
                        unwatched. This is a fault on our side rather than a
                        problem with your account, and it does not mean you are
                        out of credit. Try again shortly.
                      type: server_error
                      param: null
                      code: balance_unavailable
                      request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
        '504':
          description: The request ran past the request deadline and was terminated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: >-
                    This request ran longer than the 540 second limit and was
                    terminated. Reduce the amount of work in one call, or stream
                    the response, and try again.
                  type: server_error
                  param: null
                  code: request_deadline_exceeded
                  request_id: REQUEST_ID
          headers:
            x-hopscotch-request-id:
              $ref: '#/components/headers/RequestId'
      security:
        - customerApiKey: []
      servers:
        - url: https://api.hopscotchlabs.ai
          description: Production
components:
  headers:
    ServedBy:
      description: >-
        The full id, "{provider}/{model}", of the model that actually answered:
        the id you pinned, or the member of the routing profile that served.
        Present on every served reply, streamed or not, which is the only place
        a streamed request can read it.
      schema:
        type: string
        example: openai/gpt-4o-mini
    ServedVia:
      description: >-
        Present, with the value `backup`, when a backup route served this
        request. Absent on every other response, and never sent with any other
        value, so a client that has never read it sees nothing change about an
        ordinary request. The provider named on x-hopscotch-provider and in the
        body is still the one you asked for.
      schema:
        type: string
        enum:
          - backup
        example: backup
    RequestId:
      description: >-
        Our id for this request. Quote it when you contact support. Present on
        every response, errors included.
      schema:
        type: string
    SdkRequestId:
      description: >-
        The same value as x-hopscotch-request-id, on the header the official
        OpenAI SDKs surface on their error objects.
      schema:
        type: string
    Provider:
      description: Which provider answered.
      schema:
        type: string
    RetryAttemptCount:
      description: How many attempts were made before the response you received.
      schema:
        type: string
    CacheStatus:
      description: Whether the reply came from cache.
      schema:
        type: string
    TraceId:
      description: A trace id for this request.
      schema:
        type: string
  schemas:
    TextCompletion:
      type: object
      description: An OpenAI text completion, as the provider produced it.
      additionalProperties: true
      properties:
        id:
          type: string
        object:
          type: string
          example: text_completion
        created:
          type: integer
        model:
          type: string
        choices:
          type: array
          items:
            type: object
            additionalProperties: true
            properties:
              text:
                type: string
              index:
                type: integer
              logprobs:
                type: object
                nullable: true
                additionalProperties: true
              finish_reason:
                type: string
                nullable: true
        usage:
          type: object
          additionalProperties: true
    Error:
      type: object
      description: The error envelope. One top-level `error` key, always, at every status.
      required:
        - error
      additionalProperties: false
      properties:
        error:
          type: object
          required:
            - message
            - type
            - param
            - code
          additionalProperties: false
          properties:
            message:
              type: string
              description: Prose for a person. It may be reworded, so do not branch on it.
            type:
              type: string
              description: The category an SDK branches on. A closed set.
              enum:
                - invalid_request_error
                - authentication_error
                - permission_error
                - not_found_error
                - rate_limit_error
                - api_error
                - insufficient_quota
                - server_error
            param:
              type: string
              nullable: true
              description: >-
                The request field at fault, or null. Present and null rather
                than absent.
            code:
              type: string
              nullable: true
              description: The stable machine-readable reason. Branch on this.
            request_id:
              type: string
              description: >-
                Our id for this request, the same value as the
                x-hopscotch-request-id header. Quote it when you contact
                support.
  securitySchemes:
    customerApiKey:
      type: http
      scheme: bearer
      description: >-
        A workspace API key in an `Authorization: Bearer` header. A missing
        header, a scheme other than Bearer, a key of the wrong shape, and a key
        we reject are all 401.

````

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