openapi: 3.0.3
info:
  title: Aurora Inference API
  version: 1.0.0
  description: |
    Discover available models and generate text with OpenAI-compatible chat and
    text completions. See https://docs.aur.lu/docs/inference/getting-started for
    authentication and your first request.
servers:
  - url: https://ai.aur.lu/v1
    description: Aurora Inference
security:
  - PortalToken: []
tags:
  - name: Models
    description: Discover the public model catalog.
  - name: Completions
    description: Generate text using an available model.
paths:
  /models:
    get:
      operationId: listInferenceModels
      summary: List available models
      description: >-
        Returns the models enabled by default. No authentication is required. When the request carries an API token, the response applies the tenant's model overrides instead.
      security:
        - {}
        - PortalToken: []
      tags: [Models]
      responses:
        '200':
          description: Available model catalog (may be empty).
          content:
            application/json:
              schema:
                type: object
                required: [object, data]
                properties:
                  object:
                    type: string
                    enum: [list]
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Model'
        '500':
          $ref: '#/components/responses/InternalError'
  /models/{model}:
    get:
      operationId: getInferenceModel
      summary: Retrieve a model
      description: |
        Use the exact ID from GET /models. IDs can contain slashes (for example,
        deepseek/deepseek-v4-flash).
        Without authentication, only models enabled by default are returned; with an API
        token, the tenant's model overrides apply.
      security:
        - {}
        - PortalToken: []
      tags: [Models]
      parameters:
        - name: model
          in: path
          required: true
          description: Model ID from the catalog, including any organization prefix.
          schema:
            type: string
          example: deepseek/deepseek-v4-flash
      responses:
        '200':
          description: Model metadata.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
  /chat/completions:
    post:
      operationId: createInferenceChatCompletion
      summary: Create a chat completion
      tags: [Completions]
      description: |
        Requires the execute:inference:requests permission and access to inference.
        Prepaid accounts must have positive inference credit. Select a model from
        GET /models; tool calling, structured output, and multimodal input support
        depend on the selected model.

        With stream=true, the response is an SSE stream of JSON chat completion
        chunks with choices[].delta, followed by data: [DONE].
        Clients must accept usage-only chunks with an empty choices array.
        Errors before streaming use an HTTP error response;
        an interrupted stream is not a complete response.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChatCompletionRequest'
            example:
              model: deepseek/deepseek-v4-flash
              messages:
                - role: user
                  content: Say hello in one sentence.
              max_tokens: 128
      responses:
        '200':
          description: 'A JSON chat completion, or SSE chunks when stream=true. Streaming ends with data: [DONE].'
          headers:
            X-Aurora-Resolved-Model:
              description: Canonical model selected for this request. The response body retains the requested model ID or alias.
              schema: {type: string}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatCompletion'
              example:
                id: chatcmpl-example
                object: chat.completion
                created: 1788998400
                model: deepseek/deepseek-v4-flash
                choices:
                  - index: 0
                    message: {role: assistant, content: 'Hello! How can I help you today?'}
                    finish_reason: stop
                usage: {prompt_tokens: 14, completion_tokens: 10, total_tokens: 24}
            text/event-stream:
              schema:
                type: string
                description: SSE data frames contain JSON chunks with id, object=chat.completion.chunk, created, model, choices (index, delta, finish_reason), and optional usage. Delta may contain content, role, reasoning extensions, or partial tool_calls (index, id, type, function name/arguments). Accumulate fragments before parsing tool arguments.
              example: |
                data: {"id":"chatcmpl-example","object":"chat.completion.chunk","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello!"},"finish_reason":null}]}

                data: {"id":"chatcmpl-example","object":"chat.completion.chunk","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

                data: {"id":"chatcmpl-example","object":"chat.completion.chunk","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":2,"total_tokens":16}}

                data: [DONE]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/Unavailable'
  /completions:
    post:
      operationId: createInferenceCompletion
      summary: Create a text completion
      tags: [Completions]
      description: |
        Generate text from a prompt. Requires the execute:inference:requests
        permission and access to inference. Prepaid accounts must have positive
        inference credit. Select a model from GET /models; support depends on
        the selected model.

        With stream=true, the response is an SSE stream of JSON text completion
        chunks with choices[].text, followed by data: [DONE]. Clients must accept
        usage-only chunks with an empty choices array. Errors before streaming
        use an HTTP error response; an interrupted stream is not a complete response.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompletionRequest'
            example:
              model: deepseek/deepseek-v4-flash
              prompt: Once upon a time
              max_tokens: 128
      responses:
        '200':
          description: 'A JSON text completion, or SSE chunks when stream=true. Streaming ends with data: [DONE].'
          headers:
            X-Aurora-Resolved-Model:
              description: Canonical model selected for this request. The response body retains the requested model ID or alias.
              schema: {type: string}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Completion'
              example:
                id: cmpl-example
                object: text_completion
                created: 1788998400
                model: deepseek/deepseek-v4-flash
                choices:
                  - index: 0
                    text: ', there was a friendly dragon.'
                    finish_reason: stop
                    logprobs: null
                usage: {prompt_tokens: 4, completion_tokens: 7, total_tokens: 11}
            text/event-stream:
              schema:
                type: string
                description: SSE data frames contain JSON chunks with id, object=text_completion, created, model, choices (index, text, finish_reason, logprobs), and optional usage.
              example: |
                data: {"id":"cmpl-example","object":"text_completion","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[{"index":0,"text":", there was a friendly dragon.","finish_reason":null,"logprobs":null}]}

                data: {"id":"cmpl-example","object":"text_completion","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[{"index":0,"text":"","finish_reason":"stop","logprobs":null}]}

                data: {"id":"cmpl-example","object":"text_completion","created":1788998400,"model":"deepseek/deepseek-v4-flash","choices":[],"usage":{"prompt_tokens":4,"completion_tokens":7,"total_tokens":11}}

                data: [DONE]
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          $ref: '#/components/responses/BadGateway'
        '503':
          $ref: '#/components/responses/Unavailable'
components:
  securitySchemes:
    PortalToken:
      type: http
      scheme: bearer
      bearerFormat: Aurora portal token (atp_...)
      description: 'For generation, create a portal API token with execute:inference:requests. Send Authorization: Bearer atp_your_key. The token is shown only once at creation.'
  schemas:
    Model:
      type: object
      required: [id, object, name, created, pricing, context_length]
      properties:
        id: {type: string, description: Public model ID to pass in completion requests., example: deepseek/deepseek-v4-flash}
        aliases:
          type: array
          items: {type: string}
          description: Compatibility names accepted for this model. Aliases share its availability, capabilities and pricing; they do not preserve older model behavior.
        resolved_model:
          type: string
          description: Canonical model ID when this detail response was requested using an alias. The id field retains the requested alias.
        object: {type: string, enum: [model]}
        canonical_slug: {type: string}
        hugging_face_id: {type: string, nullable: true}
        name: {type: string}
        created: {type: integer, format: int64, description: Creation time as Unix seconds.}
        description: {type: string}
        input_modalities: {type: array, nullable: true, items: {type: string}}
        output_modalities: {type: array, nullable: true, items: {type: string}}
        context_length: {type: integer, format: int64, description: Context window in tokens.}
        max_output_tokens: {type: integer, format: int64, description: Configured maximum output tokens; zero means unspecified.}
        pricing:
          $ref: '#/components/schemas/Pricing'
        per_request_limits:
          description: Model-specific request limits; may be null.
        supported_sampling_parameters: {type: array, nullable: true, items: {type: string}}
        supported_features: {type: array, nullable: true, items: {type: string}}
        architecture:
          $ref: '#/components/schemas/Architecture'
        license: {type: string}
        license_url: {type: string}
        model_card: {type: string}
    Architecture:
      type: object
      description: OpenRouter-compatible summary of the model's modalities, derived from input_modalities and output_modalities.
      required: [modality, input_modalities, output_modalities]
      properties:
        modality: {type: string, description: Input and output modalities joined with '+' and separated by '->'., example: text->text}
        input_modalities: {type: array, items: {type: string}}
        output_modalities: {type: array, items: {type: string}}
    Pricing:
      type: object
      description: Decimal USD prices encoded as strings. Token prices are per token, not per million tokens. Additional pricing dimensions may be present.
      required: [prompt, completion, input_cache_read]
      properties:
        prompt: {type: string, example: '0.0000001'}
        completion: {type: string, example: '0.0000002'}
        input_cache_read: {type: string, example: '0.00000005'}
    GenerationOptions:
      type: object
      required: [model]
      additionalProperties: true
      description: Supported options and defaults depend on the selected model.
      properties:
        model: {type: string, description: Exact public ID or compatibility alias from GET /models.}
        stream: {type: boolean, default: false}
        stream_options:
          type: object
          properties:
            include_usage: {type: boolean, description: Streaming responses include usage information. Clients must accept usage-only chunks with an empty choices array.}
          additionalProperties: true
        max_tokens: {type: integer, minimum: 1, description: Maximum generated tokens; model-dependent limits apply.}
        temperature: {type: number, description: Sampling temperature; range and default depend on the selected model.}
        top_p: {type: number, description: Nucleus sampling probability.}
        n: {type: integer, minimum: 1, description: Number of choices where supported.}
        stop:
          description: Stop sequence or sequences where supported.
          oneOf:
            - type: string
              nullable: true
            - type: array
              items: {type: string}
        presence_penalty: {type: number}
        frequency_penalty: {type: number}
        seed: {type: integer, format: int64}
        user: {type: string, description: Optional end-user identifier.}
    ChatCompletionRequest:
      example:
        model: deepseek/deepseek-v4-flash
        messages:
          - role: user
            content: Say hello in one sentence.
        max_tokens: 128
      allOf:
        - $ref: '#/components/schemas/GenerationOptions'
        - type: object
          required: [messages]
          properties:
            messages:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/ChatMessage'
            max_completion_tokens: {type: integer, minimum: 1, description: Model-dependent alternative to max_tokens.}
            tools:
              type: array
              items:
                $ref: '#/components/schemas/Tool'
            tool_choice:
              description: auto, none, required, or an object selecting a function; model-dependent.
              oneOf:
                - type: string
                  enum: [auto, none, required]
                - type: object
                  properties:
                    type: {type: string, enum: [function]}
                    function:
                      type: object
                      properties:
                        name: {type: string}
            parallel_tool_calls: {type: boolean}
            response_format:
              type: object
              description: Model-dependent format, such as text, json_object, or json_schema.
              properties:
                type: {type: string}
                json_schema: {type: object, additionalProperties: true}
              additionalProperties: true
    ChatMessage:
      type: object
      required: [role]
      additionalProperties: true
      properties:
        role: {type: string, enum: [system, developer, user, assistant, tool]}
        content:
          description: Text or model-supported content parts. May be null for assistant tool calls.
          oneOf:
            - type: string
              nullable: true
            - type: array
              items:
                type: object
                required: [type]
                properties:
                  type: {type: string}
                  text: {type: string}
                  image_url:
                    type: object
                    properties:
                      url: {type: string}
                      detail: {type: string}
                additionalProperties: true
        name: {type: string}
        tool_call_id: {type: string, description: Required for a tool result; matches the assistant tool call ID.}
        tool_calls:
          type: array
          items:
            $ref: '#/components/schemas/ToolCall'
    Tool:
      type: object
      required: [type, function]
      properties:
        type: {type: string, enum: [function]}
        function:
          type: object
          required: [name]
          properties:
            name: {type: string}
            description: {type: string}
            parameters: {type: object, additionalProperties: true, description: JSON Schema describing function arguments.}
            strict: {type: boolean, description: Model-dependent strict schema enforcement.}
    ToolCall:
      type: object
      required: [id, type, function]
      properties:
        id: {type: string}
        type: {type: string, enum: [function]}
        function:
          type: object
          required: [name, arguments]
          properties:
            name: {type: string}
            arguments: {type: string, description: JSON-encoded arguments. Validate before executing a tool.}
    CompletionRequest:
      example:
        model: deepseek/deepseek-v4-flash
        prompt: Once upon a time
        max_tokens: 128
      allOf:
        - $ref: '#/components/schemas/GenerationOptions'
        - type: object
          required: [prompt]
          properties:
            prompt:
              description: Text, a batch of texts, token IDs, or a batch of token ID sequences; model support varies.
              oneOf:
                - type: string
                - type: array
                  items: {type: string}
                - type: array
                  items: {type: integer}
                - type: array
                  items:
                    type: array
                    items: {type: integer}
            echo: {type: boolean}
            suffix: {type: string, nullable: true}
            logprobs: {type: integer, nullable: true}
            best_of: {type: integer, minimum: 1}
    Completion:
      allOf:
        - $ref: '#/components/schemas/CompletionBase'
        - type: object
          properties:
            object: {type: string, enum: [text_completion]}
            choices:
              type: array
              items:
                type: object
                properties:
                  index: {type: integer}
                  text: {type: string}
                  finish_reason: {type: string, nullable: true}
                  logprobs: {type: object, nullable: true, additionalProperties: true}
    CompletionBase:
      type: object
      required: [id, object, created, model, choices]
      additionalProperties: true
      properties:
        id: {type: string}
        object: {type: string}
        created: {type: integer, format: int64, description: Unix timestamp in seconds.}
        model: {type: string, description: Public model ID.}
        usage:
          $ref: '#/components/schemas/Usage'
    ChatCompletion:
      allOf:
        - $ref: '#/components/schemas/CompletionBase'
        - type: object
          properties:
            object: {type: string, enum: [chat.completion]}
            choices:
              type: array
              items:
                type: object
                properties:
                  index: {type: integer}
                  message:
                    $ref: '#/components/schemas/ChatMessage'
                  finish_reason: {type: string, nullable: true, description: 'For example stop, length, tool_calls, or content_filter.'}
                  logprobs: {type: object, nullable: true, additionalProperties: true}
    Usage:
      type: object
      nullable: true
      additionalProperties: true
      properties:
        prompt_tokens: {type: integer, format: int64}
        completion_tokens: {type: integer, format: int64}
        total_tokens: {type: integer, format: int64}
        prompt_tokens_details:
          type: object
          additionalProperties: true
          properties:
            cached_tokens: {type: integer, format: int64}
        completion_tokens_details: {type: object, additionalProperties: true}
    InferenceError:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [message, type]
          additionalProperties: true
          properties:
            message: {type: string}
            type: {type: string, description: 'Error types include invalid_request_error, billing_error, internal_error, server_error, and service_unavailable.'}
      example:
        error: {message: insufficient prepaid inference credit, type: billing_error}
    MessageError:
      type: object
      required: [message]
      properties:
        message: {type: string}
      example: {message: 'Missing permission execute:inference:requests'}
  responses:
    Unauthorized:
      description: Missing, invalid, or expired bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/MessageError'
    Forbidden:
      description: Missing required permission or account access to inference.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/MessageError'
              - $ref: '#/components/schemas/InferenceError'
    BadRequest:
      description: Invalid request. Send an application/json body with the required fields.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
    PaymentRequired:
      description: Insufficient prepaid inference credit. Add credits in the Portal before retrying.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
          example:
            error: {message: insufficient prepaid inference credit, type: billing_error}
    NotFound:
      description: Unknown or unavailable model, or unsupported endpoint. Refresh GET /models to discover available IDs.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
          example:
            error: {message: model not found, type: invalid_request_error}
    RateLimited:
      description: Request rate limit exceeded. Retry after a delay.
      content:
        application/json:
          schema: {}
    InternalError:
      description: The service could not process the request.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
    BadGateway:
      description: The service could not complete the inference request. Retry after a delay.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
    Unavailable:
      description: Service is temporarily unavailable. Retry after the indicated delay.
      headers:
        Retry-After:
          description: Suggested delay in seconds before retrying.
          schema: {type: integer, minimum: 0}
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/InferenceError'
          example:
            error: {message: service temporarily unavailable, type: service_unavailable}
