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

# Create a chat completion

> Sends a conversation to a model and returns the model's reply, whole or as a stream. The request and the reply follow OpenAI's chat completions format. Each field below notes where Morse differs.

Before the call, the account must hold enough credit for the most the request could cost, which is the prompt plus the output limit at the model's prices. After the call, the account pays for the tokens the provider reports. If a stream stops early, the account pays for what the stream delivered. A retried request that reached the model costs again. Each reply's X-Request-Id identifies the request.



## OpenAPI

````yaml /openapi.json post /v1/chat/completions
openapi: 3.1.1
info:
  title: Morse API
  version: '1'
  description: >-
    The Morse API serves chat, image, web search, and page-reading models
    through an OpenAI-compatible interface. Each request pays with your Morse
    account's credits.


    Send an API key from the Morse app with every request, in the Authorization
    header as Bearer sk_morse_.... A key acts for its account and always pays
    with credits, never with a plan's included use. One credit is $0.01. GET
    /v1/models lists prices in micro-dollars, 10,000 to the credit. Keep keys on
    your server. Browsers on other sites cannot call the API.


    All of an account's keys and its owner's use of the Morse app share one
    budget of requests per minute and one limit on requests in flight. The
    account's plan sets both. A request refused for either limit carries
    Retry-After, the number of seconds to wait. A retried POST is a new request,
    and the API charges it again.


    An error reply is JSON in the Error shape, with a stable code. A path the
    API does not serve returns 404 as plain text, and a wrong method returns 405
    as plain text.
servers:
  - url: https://api.trymorse.ai
security:
  - apiKey: []
paths:
  /v1/chat/completions:
    post:
      summary: Create a chat completion
      description: >-
        Sends a conversation to a model and returns the model's reply, whole or
        as a stream. The request and the reply follow OpenAI's chat completions
        format. Each field below notes where Morse differs.


        Before the call, the account must hold enough credit for the most the
        request could cost, which is the prompt plus the output limit at the
        model's prices. After the call, the account pays for the tokens the
        provider reports. If a stream stops early, the account pays for what the
        stream delivered. A retried request that reached the model costs again.
        Each reply's X-Request-Id identifies the request.
      operationId: createChatCompletion
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
            example:
              model: kimi-k3
              messages:
                - role: system
                  content: Answer in one sentence.
                - role: user
                  content: What does a TEE attest?
              max_completion_tokens: 200
      responses:
        '200':
          description: >-
            The reply. When stream is true, the body is server-sent events. Each
            data line is a ChatCompletionChunk, and the stream ends with data:
            [DONE]. If the provider fails after the first event, the stream ends
            with one error event in the Error shape and no [DONE]. Some
            reasoning models send a : keepalive comment every 25 seconds while
            they reason.
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
            X-Funding:
              $ref: '#/components/headers/X-Funding'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            X-Output-Limited:
              $ref: '#/components/headers/X-Output-Limited'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatCompletion'
              example:
                id: chatcmpl-YYOKD77FV2J75JOVRH6T77B4GZ
                object: chat.completion
                created: 1792187800
                model: kimi-k3
                choices:
                  - index: 0
                    message:
                      role: assistant
                      content: >-
                        A TEE attests which code runs inside it, signed by keys
                        the hardware vendor vouches for.
                    finish_reason: stop
                usage:
                  prompt_tokens: 24
                  completion_tokens: 19
                  total_tokens: 43
            text/event-stream:
              schema:
                type: string
              x-event-schema:
                oneOf:
                  - $ref: '#/components/schemas/ChatCompletionChunk'
                  - $ref: '#/components/schemas/Error'
              example: >+
                data:
                {"id":"chatcmpl-YYOKD77FV2J75JOVRH6T77B4GZ","object":"chat.completion.chunk","created":1792187800,"model":"kimi-k3","choices":[{"index":0,"delta":{"content":"A
                TEE"},"finish_reason":null}],"obfuscation":"Xg7U0KyODYismlz2"}


                data:
                {"id":"chatcmpl-YYOKD77FV2J75JOVRH6T77B4GZ","object":"chat.completion.chunk","created":1792187800,"model":"kimi-k3","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"obfuscation":"NYdsGQw6HoQVX7pCODcrHz43"}


                data:
                {"id":"chatcmpl-YYOKD77FV2J75JOVRH6T77B4GZ","object":"chat.completion.chunk","created":1792187800,"model":"kimi-k3","choices":[],"usage":{"prompt_tokens":24,"completion_tokens":19,"total_tokens":43},"obfuscation":"Uy9SG40zNe5p8eJh"}


                data: [DONE]

        '400':
          description: The request is malformed, or the model or its provider refused it.
          x-error-codes:
            - code: invalid_request_body
              when: >-
                The body is not a JSON object, a field has the wrong JSON type,
                or model is missing.
            - code: invalid_parameter
              when: >-
                A field has a value the endpoint refuses. The message names the
                field.
            - code: duplicate_json_key
              when: A JSON object in the body repeats a key.
            - code: too_many_messages
              when: messages holds more than 4,096 entries.
            - code: request_too_complex
              when: The body holds more than 262,144 JSON values.
            - code: invalid_output_limit
              when: max_tokens or max_completion_tokens is not a positive integer.
            - code: invalid_request
              when: >-
                A message, part, or tool has a shape the model does not take, or
                the provider refused the request.
            - code: remote_media
              when: 'A media part links a URL instead of a data: URL.'
            - code: message_too_long
              when: >-
                In a chat with a character, the last user message holds more
                than 8,000 bytes of text.
            - code: context_length_exceeded
              when: The conversation is too long for the model.
            - code: content_filter
              when: The model provider declined the request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: Media must be attached as inline data, not linked by URL.
                  type: invalid_request_error
                  param: null
                  code: remote_media
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '401':
          description: The key is missing or wrong.
          x-error-codes:
            - code: invalid_api_key
              when: >-
                The Authorization header is missing or not Bearer, the key is
                unknown or revoked, or a token that starts with sk_ is not a
                whole sk_morse_ key.
            - code: invalid_token
              when: >-
                The bearer token is not a Morse API key. Send the whole
                sk_morse_ key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: Incorrect API key provided.
                  type: invalid_request_error
                  param: null
                  code: invalid_api_key
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '402':
          description: The account's credits do not cover the request.
          x-error-codes:
            - code: insufficient_balance
              when: >-
                The balance is below the amount the request must hold. While the
                balance is negative, the API refuses every metered request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: >-
                    The account balance does not cover the most this request
                    could cost. Add credit, or set max_tokens or
                    max_completion_tokens to lower the amount held.
                  type: insufficient_balance
                  param: null
                  code: insufficient_balance
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '403':
          description: The key's account may not make this request.
          x-error-codes:
            - code: account_disabled
              when: Morse has disabled the key's account.
            - code: account_deleted
              when: The key's account has been deleted.
            - code: account_under_18
              when: The account's owner said they are under 18.
            - code: model_requires_plan
              when: >-
                The model needs a higher plan than the account's, even when
                credits pay for the request.
            - code: characters_app_only
              when: >-
                The first system message opens with the prompt of a Morse
                character. Morse characters are available only in the Morse app,
                not through an API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: This account has been disabled. Contact support.
                  type: invalid_request_error
                  param: null
                  code: account_disabled
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '404':
          description: The model does not exist, or it is not a model for this endpoint.
          x-error-codes:
            - code: model_not_found
              when: No model of this endpoint's type has that name.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: The requested model does not exist.
                  type: invalid_request_error
                  param: null
                  code: model_not_found
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '408':
          description: The request body arrived too slowly.
          x-error-codes:
            - code: request_timeout
              when: The request body did not arrive within one minute.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: The request body did not arrive in time.
                  type: invalid_request_error
                  param: null
                  code: request_timeout
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '413':
          description: The request body is too large.
          x-error-codes:
            - code: request_too_large
              when: The body is over 32 MiB, or too large for the provider.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: Request body is too large.
                  type: invalid_request_error
                  param: null
                  code: request_too_large
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
        '429':
          description: >-
            The account is over its rate limit or its concurrency limit. Wait
            the number of seconds in Retry-After, then retry.
          x-error-codes:
            - code: rate_limit_exceeded
              when: >-
                The account used up its requests per minute. All of the
                account's keys and its owner's use of the Morse app share one
                budget.
            - code: concurrency_limit_exceeded
              when: >-
                The account already has its maximum number of requests in
                flight. Retry-After is 1.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: >-
                    Rate limit reached for this account. Retry after the time in
                    the Retry-After header.
                  type: requests
                  param: null
                  code: rate_limit_exceeded
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
        '502':
          description: The model provider failed.
          x-error-codes:
            - code: upstream_error
              when: The provider failed or did not answer.
            - code: upstream_unavailable
              when: >-
                The provider is unavailable right now. Retry later, or choose
                another model.
            - code: upstream_retention
              when: >-
                A zero-retention model's provider did not confirm zero data
                retention.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: The upstream model server failed.
                  type: upstream_error
                  param: null
                  code: upstream_error
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '503':
          description: >-
            Morse or the provider is busy or unavailable. Retry the request
            later.
          x-error-codes:
            - code: service_unavailable
              when: Morse could not start the request. Retry it.
            - code: server_busy
              when: Morse is busy. Retry-After is 1.
            - code: upstream_busy
              when: The provider is overloaded. Try again shortly.
            - code: upstream_unattested
              when: Morse could not verify the attested endpoint. Try again shortly.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error:
                  message: >-
                    The service is temporarily unable to authorize requests. Try
                    again shortly.
                  type: server_error
                  param: null
                  code: service_unavailable
          headers:
            X-Morse-Version:
              $ref: '#/components/headers/X-Morse-Version'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
components:
  schemas:
    ChatCompletionRequest:
      type: object
      required:
        - model
        - messages
      description: >-
        Only the fields below reach the model. Morse drops every other field
        without an error, such as temperature, top_p, n, stop, seed,
        response_format, logprobs, or user.
      properties:
        model:
          type: string
          minLength: 1
          description: A chat model's id from GET /v1/models.
        messages:
          type: array
          maxItems: 4096
          items:
            $ref: '#/components/schemas/ChatMessage'
        stream:
          type: boolean
          default: false
          description: Send the reply as server-sent events.
        stream_options:
          type: object
          properties:
            include_usage:
              type: boolean
              default: false
              description: >-
                Send a last chunk with usage and an empty choices array before
                [DONE]. Without it, the stream carries no usage.
        max_completion_tokens:
          type:
            - integer
            - 'null'
          minimum: 1
          description: >-
            The most output tokens the model may produce. Morse lowers a value
            above the model's max_output_tokens to max_output_tokens. When
            neither limit is set, the model's default applies. The account must
            hold credit for the most the request could cost, so a lower limit
            holds less credit.
        max_tokens:
          type:
            - integer
            - 'null'
          minimum: 1
          description: >-
            The same as max_completion_tokens. When both are set,
            max_completion_tokens wins.
        reasoning_effort:
          type: string
          description: >-
            How much a reasoning model reasons, such as low, medium, or high.
            Anthropic, Gemini, and OpenAI models use the nearest effort they
            support. When reasoning_effort is absent, the model's default
            applies.
        tools:
          type: array
          items:
            $ref: '#/components/schemas/Tool'
        tool_choice:
          description: auto, none, required, or one named function.
          oneOf:
            - type: string
              enum:
                - auto
                - none
                - required
            - type: object
              required:
                - type
                - function
              properties:
                type:
                  const: function
                function:
                  type: object
                  required:
                    - name
                  properties:
                    name:
                      type: string
        parallel_tool_calls:
          type: boolean
    ChatCompletion:
      type: object
      required:
        - id
        - object
        - model
        - choices
      description: >-
        The reply. id is a new chatcmpl- id, and model is the id you sent. The
        exception is tee models, whose reply comes unchanged from the attested
        server.
      properties:
        id:
          type: string
        object:
          const: chat.completion
        created:
          type: integer
          description: Unix seconds.
        model:
          type: string
        choices:
          type: array
          items:
            type: object
            required:
              - index
              - message
              - finish_reason
            properties:
              index:
                type: integer
              message:
                type: object
                required:
                  - role
                properties:
                  role:
                    const: assistant
                  content:
                    type:
                      - string
                      - 'null'
                  refusal:
                    type:
                      - string
                      - 'null'
                  tool_calls:
                    type: array
                    items:
                      type: object
              finish_reason:
                type:
                  - string
                  - 'null'
                description: stop, length, tool_calls, or content_filter.
        usage:
          $ref: '#/components/schemas/Usage'
    Error:
      type: object
      description: >-
        Every JSON error reply has this shape. Branch on code, which is stable.
        The message is for people and can change.
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - message
            - type
            - param
            - code
          properties:
            message:
              type: string
              description: A sentence that says what went wrong and what to do.
            type:
              type: string
              description: >-
                The error's family, such as invalid_request_error,
                insufficient_balance, plan, requests, upstream_error, or
                server_error. plan means the account's plan does not allow the
                model, even when credits pay for the request.
            param:
              type:
                - string
                - 'null'
              description: Always null on the endpoints documented here.
            code:
              type: string
              description: >-
                The specific error. Each operation lists the codes it can
                return.
    ChatMessage:
      type: object
      required:
        - role
      description: >-
        One message of the conversation. Morse keeps content and tool_calls on
        an assistant message, content and tool_call_id on a tool message, and
        only content on every other role. It drops name.
      properties:
        role:
          type: string
          description: system, developer, user, assistant, or tool.
        content:
          description: >-
            Text, or an array of content parts. Media must be inline. If an
            image_url, video_url, audio_url, or file_url part has a URL that
            does not start with data:, Morse refuses the request with
            remote_media. A file part may carry only file_data and filename.
          oneOf:
            - type: string
            - type: array
              items:
                $ref: '#/components/schemas/ContentPart'
            - type: 'null'
        tool_calls:
          type: array
          items:
            type: object
          description: >-
            The tool calls an assistant message made, as the model returned
            them.
        tool_call_id:
          type: string
          description: On a tool message, the id of the tool call it answers.
    Tool:
      type: object
      required:
        - type
        - function
      properties:
        type:
          const: function
        function:
          type: object
          required:
            - name
          properties:
            name:
              type: string
            description:
              type: string
            parameters:
              type: object
              description: A JSON Schema object for the function's arguments.
    Usage:
      type: object
      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
          properties:
            cached_tokens:
              type: integer
        completion_tokens_details:
          type: object
          properties:
            reasoning_tokens:
              type: integer
    ContentPart:
      type: object
      required:
        - type
      description: >-
        A part of a message's content. Anthropic, Gemini, and OpenAI models take
        text parts, and image_url parts with base64 JPEG, PNG, GIF, or WebP data
        URLs and detail set to auto, low, or high. Other part types reach only
        the models that read them.
      properties:
        type:
          type: string
          description: text, image_url, or another part type the model reads.
        text:
          type: string
        image_url:
          type: object
          required:
            - url
          properties:
            url:
              type: string
              description: 'A data: URL, such as data:image/png;base64,iVBORw0KGgo...'
            detail:
              type: string
              enum:
                - auto
                - low
                - high
  headers:
    X-Morse-Version:
      description: The running build. Every reply carries it.
      schema:
        type: string
    X-Funding:
      description: >-
        What pays for the request. With a key, the value is always credits. A
        request that Morse refuses before it bills anything has no X-Funding.
      schema:
        type: string
        enum:
          - credits
          - included
    X-Request-Id:
      description: >-
        An id for this request. Quote it when you contact support about the
        request. An error that arrives after the request starts carries it too.
        A request that Morse refuses before it bills anything has no
        X-Request-Id.
      schema:
        type: string
    X-Output-Limited:
      description: >-
        Set to balance when Morse lowered the output limit so that the request
        fits the account's credits.
      schema:
        const: balance
    Retry-After:
      description: Whole seconds to wait before retrying, at least 1.
      schema:
        type: integer
        minimum: 1
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: sk_morse_...
      description: An API key from the Morse app. It starts with sk_morse_.

````

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