openapi: 3.1.0
info:
  title: Hummic Upload API
  version: 0.1.0
  summary: Receive Hummic meeting audio recordings.
  description: |
    P0 Hummic devices upload one completed Ogg Opus recording to a user-owned HTTP endpoint.
    The transport is multipart/form-data. Future resumable upload support is planned around tus.
servers:
  - url: http://localhost:8789
    description: Local reference receiver (examples/upload-server/server.py).
  - url: https://your-endpoint.example
    description: Replace with your own HTTPS upload endpoint.
paths:
  /upload:
    post:
      summary: Receive one completed Hummic recording.
      operationId: uploadRecording
      security:
        - bearerAuth: []
        - {}
      parameters:
        - name: X-Hummic-Device-Id
          in: header
          required: false
          schema:
            type: string
          example: meeting-room-01
        - name: X-Hummic-Recording-Id
          in: header
          required: false
          schema:
            type: string
          example: R00000001
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
                - device_id
                - recording_id
                - format
                - sample_rate
                - channels
              properties:
                file:
                  type: string
                  format: binary
                  description: Ogg Opus recording payload.
                device_id:
                  type: string
                  example: meeting-room-01
                recording_id:
                  type: string
                  example: R00000001
                started_at:
                  type: string
                  description: ISO 8601 start time on devices with an RTC; boot-relative (e.g. boot+12s) otherwise.
                  example: "2026-05-29T15:30:00+08:00"
                ended_at:
                  type: string
                  description: ISO 8601 end time on devices with an RTC; boot-relative otherwise.
                  example: "2026-05-29T15:45:00+08:00"
                format:
                  type: string
                  enum: [opus]
                sample_rate:
                  type: integer
                  example: 16000
                channels:
                  type: integer
                  example: 2
                segment_index:
                  type: integer
                  example: 0
                segment_count:
                  type: integer
                  example: 1
            encoding:
              file:
                contentType: audio/ogg
      responses:
        "200":
          description: Upload accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadSuccess"
              examples:
                ok:
                  value:
                    ok: true
                    upload_id: R00000001
        "401":
          description: Bearer token missing or invalid.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadError"
        "403":
          description: Bearer token valid but not allowed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UploadError"
        "408":
          description: Retryable timeout.
        "429":
          description: Retryable rate limit.
        "500":
          description: Retryable server error.
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
  schemas:
    UploadSuccess:
      type: object
      required: [ok]
      properties:
        ok:
          type: boolean
          const: true
        upload_id:
          type: string
          example: R00000001
    UploadError:
      type: object
      required: [ok, error]
      properties:
        ok:
          type: boolean
          const: false
        error:
          type: string
          example: invalid_token
