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

# Handle an Anthropic Messages-compatible request, streaming or returning the assembled response



## OpenAPI

````yaml /openapi/v1.json post /messages
openapi: 3.1.0
info:
  title: HASP AI API
  version: '2026-07-12'
  description: >-
    The HASP Public AI API is the regulated-AI substrate for healthcare and
    other

    regulated industries — identity, policy, audit, compliance, and PHI handling

    for AI inference, exposed via two surfaces:


    - **Native (`/v1/ai/*`)**: HASP-native chat with full event taxonomy, run
    lifecycle,
      and PHI metadata.
    - **Anthropic-compat (`/v1/messages`)**: Drop-in replacement for
    `@anthropic-ai/sdk` —
      change only `baseURL`. All Gateway compliance checks (BAA, credits, PHI policy) apply.

    All requests require an API key (`Authorization: Bearer
    hasp_api_live_<key>`). See

    [Authentication](https://docs.usehasp.com/ai-api/authentication) for key
    management.
servers:
  - url: https://api.usehasp.com/v1
    description: Production
security:
  - http: []
paths:
  /messages:
    post:
      tags:
        - Messages
      summary: >-
        Handle an Anthropic Messages-compatible request, streaming or returning
        the assembled response
      operationId: v1.messages
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MessagesRequest'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                anyOf:
                  - type: object
                    properties:
                      id:
                        type: string
                      type:
                        type: string
                        const: message
                      role:
                        type: string
                        const: assistant
                      content:
                        type: array
                        items:
                          anyOf:
                            - type: object
                              properties:
                                type:
                                  type: string
                                  const: text
                                text:
                                  type: string
                              required:
                                - type
                                - text
                            - type: object
                              properties:
                                type:
                                  type: string
                                  const: tool_use
                                id:
                                  anyOf:
                                    - type: string
                                    - type: string
                                      enum:
                                        - ''
                                name:
                                  anyOf:
                                    - type: string
                                    - type: string
                                      enum:
                                        - ''
                                input:
                                  anyOf:
                                    - type: string
                                    - type: array
                                      items:
                                        type: string
                                      minItems: 0
                                      maxItems: 0
                                      additionalItems: false
                              required:
                                - type
                                - id
                                - name
                                - input
                      model: {}
                      stop_reason:
                        type: string
                      stop_sequence:
                        type: 'null'
                      usage:
                        type: object
                        properties:
                          input_tokens:
                            type: integer
                          output_tokens:
                            type: integer
                          cache_creation_input_tokens:
                            type: integer
                          cache_read_input_tokens:
                            type: integer
                        required:
                          - input_tokens
                          - output_tokens
                          - cache_creation_input_tokens
                          - cache_read_input_tokens
                      meta:
                        type: object
                        properties:
                          request_id:
                            type:
                              - string
                              - 'null'
                        required:
                          - request_id
                    required:
                      - id
                      - type
                      - role
                      - content
                      - model
                      - stop_reason
                      - stop_sequence
                      - usage
                      - meta
                  - type: string
            text/event-stream:
              schema:
                type: string
          headers:
            Transfer-Encoding:
              required: true
              schema:
                type: string
                enum:
                  - chunked
        '400':
          description: ''
          content:
            application/json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    const: error
                  error:
                    type: object
                    properties:
                      type:
                        type: string
                        const: invalid_request_error
                      message:
                        type: string
                      hasp_code:
                        type: string
                        const: UNSUPPORTED_PARAMETER
                      hasp_details:
                        type: object
                        properties:
                          parameter:
                            type: string
                            const: store
                        required:
                          - parameter
                      param:
                        type: string
                        const: store
                    required:
                      - type
                      - message
                      - hasp_code
                      - hasp_details
                      - param
                required:
                  - type
                  - error
        '401':
          description: >-
            Anthropic-shaped error — bearer token missing, malformed, or
            revoked.
          content:
            application/json:
              schema:
                type: string
                examples:
                  - type: error
                    error:
                      type: authentication_error
                      message: Bearer token is missing, malformed, or revoked.
                      hasp_code: INVALID_API_KEY
                      hasp_request_id: 01JQREQ7XZQK5N6PZ1VVXHYB8T
        '403':
          $ref: '#/components/responses/AuthorizationException'
        '422':
          $ref: '#/components/responses/ValidationException'
        '429':
          description: Anthropic-shaped error — rate limit exceeded.
          content:
            application/json:
              schema:
                type: string
                examples:
                  - type: error
                    error:
                      type: rate_limit_error
                      message: Rate limit exceeded.
                      hasp_code: RATE_LIMITED
                      hasp_request_id: 01JQREQ7XZQK5N6PZ1VVXHYB8T
components:
  schemas:
    MessagesRequest:
      type: object
      description: >-
        Validates POST /v1/messages (Anthropic-compat) per PRD §05-public-api.


        Accepts Anthropic's exact wire format so existing @anthropic-ai/sdk

        integrations (including coding agents such as Claude Code, per
        ADR-YGE00M)

        need only change the baseURL: structured content blocks (text / tool_use
        /

        tool_result / image), tool definitions, and `cache_control` markers on

        system blocks, content blocks, and tool definitions.


        HASP-native flags (e.g. 'store') are rejected with 400
        UNSUPPORTED_PARAMETER

        per PRD §05: "rejecting rather than silently accepting keeps the
        contract honest."
      properties:
        model:
          type: string
          maxLength: 100
        max_tokens:
          type:
            - integer
            - 'null'
          minimum: 1
          maximum: 32000
        tool_choice:
          type:
            - string
            - 'null'
          description: >-
            Shape-validated here; normalized by
            AnthropicMessagesRequestBuilder::buildToolChoice()

            and enforced by AiGatewayService::assertParametersSupported()
            (HASP-509).
        stream:
          type:
            - boolean
            - 'null'
        temperature:
          type:
            - number
            - 'null'
          minimum: 0
          maximum: 1
        top_p:
          type:
            - number
            - 'null'
          minimum: 0
          maximum: 1
        top_k:
          type:
            - integer
            - 'null'
          minimum: 1
        provider_extensions:
          type:
            - array
            - 'null'
          description: |-
            Escape hatch for Anthropic-specific wire keys the canonical
            fields above don't (yet) model — see ADR-ZP99PX. Merged into the
            raw wire payload by DirectProviderDriver; rejected with
            UNSUPPORTED_PARAMETER on drivers that can't honor it.
          items:
            type: string
        stop_sequences:
          type:
            - array
            - 'null'
          items:
            type: string
        metadata:
          type: object
          properties:
            user_id:
              type:
                - string
                - 'null'
              maxLength: 255
        on_behalf_of:
          type: object
          description: |-
            Asserted end-user identity — a HASP extension on the Anthropic
            wire shape (Anthropic SDK users send it via `extra_body`).
            Records which user of your application took this action on the
            audit chain, as an assertion made by your integration — HASP
            does not verify it, it is never forwarded to the model
            provider, and it is never shown to the model. Distinct from
            `metadata.user_id`, which is provider metadata. Supported for
            API-key credentials only.
          properties:
            id:
              type: string
              maxLength: 256
            display:
              type:
                - string
                - 'null'
              maxLength: 256
        messages:
          type: array
          items:
            type: object
            properties:
              role:
                type: string
                enum:
                  - user
                  - assistant
              content:
                type: string
                description: >-
                  Content is either a plain string or an array of content blocks

                  (text / tool_use / tool_result / image / document) —
                  Anthropic's

                  wire format allows both; shape-level validation of individual

                  blocks is intentionally loose here (mirrors
                  ChatCompletionsRequest's

                  precedent of validating for presence, not deep block schemas).

                  cache_control lives on individual content blocks (Anthropic's
                  wire

                  convention), not on the message itself — captured verbatim as

                  part of this opaque blob when content is a block array.
                  Restricted

                  to string|array (not int/bool/etc.) so a malformed request
                  422s

                  instead of 500ing when Message::$content type-checks it.
            required:
              - role
              - content
          minItems: 1
        system:
          type: array
          description: |-
            System is either a plain string or an array of blocks carrying
            per-block cache_control (Anthropic's system-prompt caching shape).
          items:
            type: object
            properties:
              type:
                type:
                  - string
                  - 'null'
                enum:
                  - text
              text:
                type:
                  - string
                  - 'null'
              cache_control:
                type:
                  - object
                  - 'null'
                properties:
                  type:
                    type:
                      - string
                      - 'null'
                    enum:
                      - ephemeral
        tools:
          type:
            - array
            - 'null'
          items:
            type: object
            properties:
              name:
                type: string
              description:
                type:
                  - string
                  - 'null'
              input_schema:
                type:
                  - object
                  - 'null'
                properties:
                  type:
                    type:
                      - string
                      - 'null'
                    description: >-
                      Nested key so the generated OpenAPI spec renders
                      input_schema as

                      a JSON Schema object rather than a bare array.
              cache_control:
                type:
                  - object
                  - 'null'
                properties:
                  type:
                    type:
                      - string
                      - 'null'
                    enum:
                      - ephemeral
      required:
        - model
        - messages
      title: MessagesRequest
  responses:
    AuthorizationException:
      description: Authorization error
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                description: Error overview.
            required:
              - message
    ValidationException:
      description: Validation error
      content:
        application/json:
          schema:
            type: object
            properties:
              message:
                type: string
                description: Errors overview.
              errors:
                type: object
                description: A detailed description of each field that failed validation.
                additionalProperties:
                  type: array
                  items:
                    type: string
            required:
              - message
              - errors
  securitySchemes:
    http:
      type: http
      scheme: bearer

````