openapi: 3.1.0
info:
  title: Sonnely API
  version: 1.1.0
  description: Inference as a service on Robinhood Chain. Text, image, video and audio behind one key, billed in credits.
servers:
  - url: https://sonnely.com/api
  - url: http://localhost:3000/api
security:
  - bearer: []
paths:
  /v1/models:
    get:
      summary: List models
      security: []
      responses:
        "200":
          description: Model catalog
  /v1/chat/completions:
    post:
      summary: Chat completion (billed in credits)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [model, messages]
              properties:
                model:
                  type: string
                  example: sonnely-gpt
                messages:
                  type: array
                  items:
                    type: object
                    required: [role, content]
                    properties:
                      role:
                        type: string
                        enum: [system, user, assistant]
                      content:
                        type: string
                stream:
                  type: boolean
                max_tokens:
                  type: integer
      responses:
        "200":
          description: Completion + sonnely.credits_charged
        "401":
          description: Missing API key
        "402":
          description: Insufficient credits
  /v1/images/models:
    get:
      summary: List image models
      security: []
      responses:
        "200":
          description: Image catalog with per-image credits
  /v1/images/generations:
    post:
      summary: Generate images (billed per image)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [model, prompt]
              properties:
                model:
                  type: string
                  example: bytedance-seed/seedream-5-0-pro
                prompt:
                  type: string
                n:
                  type: integer
      responses:
        "200":
          description: Images + sonnely.credits_charged
        "402":
          description: Insufficient credits
  /v1/videos/models:
    get:
      summary: List video models
      security: []
      responses:
        "200":
          description: Video catalog with per-second credits
  /v1/videos/generations:
    post:
      summary: Submit async video job (charged at completion)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [model, prompt]
              properties:
                model:
                  type: string
                  example: google/veo-3.1
                prompt:
                  type: string
                duration:
                  type: integer
      responses:
        "200":
          description: Job id + poll URL + credit estimate
        "402":
          description: Insufficient credits
  /v1/videos/{jobId}:
    get:
      summary: Poll video job (charges exact cost once when completed)
      parameters:
        - name: jobId
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Job status + download URLs when completed
  /v1/audio/speech:
    post:
      summary: Text to speech (billed per character, beta)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [model, input]
              properties:
                model:
                  type: string
                  example: openai/gpt-4o-mini-tts-2025-12-15
                input:
                  type: string
                voice:
                  type: string
      responses:
        "200":
          description: Raw audio bytes
  /v1/audio/transcriptions:
    post:
      summary: Speech to text (beta flat estimate)
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
      responses:
        "200":
          description: Transcribed text
  /deposits/claim:
    post:
      summary: Claim USDG/ETH deposit for credits
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [txHash, asset, chainId]
              properties:
                txHash:
                  type: string
                asset:
                  type: string
                  enum: [USDG, ETH]
                chainId:
                  type: integer
                  enum: [4663, 46630]
      responses:
        "200":
          description: Credits owed
  /health:
    get:
      summary: Health
      security: []
      responses:
        "200":
          description: ok
components:
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
