{
  "openapi": "3.0.3",
  "info": {
    "title": "Boson AI API",
    "description": "REST API for Boson AI audio models.",
    "version": "1.0.0",
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://api.boson.ai"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/realtime/client_secrets": {
      "post": {
        "operationId": "createRealtimeClientSecret",
        "summary": "Create a client secret",
        "description": "Create a short-lived ephemeral key for a browser, mobile app, or other client-side Higgs Realtime connection. Call this endpoint from a trusted server with a valid Boson API key, then pass the returned key to the client.",
        "tags": [
          "Realtime"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRealtimeClientSecretRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A short-lived Realtime client secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RealtimeClientSecret"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body, or ephemeral keys are not enabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Billing entitlement refused. The OpenAI-style upstream error body is passed through.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Client-secret generation failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/audio/speech": {
      "post": {
        "operationId": "createSpeech",
        "summary": "Create a speech",
        "description": "Generate speech audio from text. Returns an audio file, or a stream of raw PCM chunks when `stream` is `true`. The body may be JSON or `multipart/form-data` — the latter lets you upload `ref_audio` as a raw file instead of base64-encoding it.",
        "tags": [
          "Audio"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSpeechRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "input": {
                    "type": "string",
                    "description": "Text to convert to speech."
                  },
                  "model": {
                    "type": "string",
                    "default": "higgs-tts-3"
                  },
                  "voice": {
                    "type": "string",
                    "default": "default"
                  },
                  "response_format": {
                    "type": "string",
                    "default": "mp3"
                  },
                  "ref_audio": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reference audio file for one-off cloning (AAC/WAV/MP3/FLAC/OPUS), or an http(s) URL string."
                  },
                  "ref_text": {
                    "type": "string",
                    "description": "Recommended transcript of `ref_audio`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated audio. The content type depends on `response_format`.",
            "content": {
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/ogg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/aac": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/flac": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/L16": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameters (e.g. `input_too_long`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/videos": {
      "post": {
        "operationId": "createVideo",
        "summary": "Create a video",
        "description": "Create an avatar talking-head video (async). Returns the Video object with `status: \"queued\"`; poll `GET /v1/videos/{video_id}` and download the rendered MP4 from `GET /v1/videos/{video_id}/content`. Provide a reference image plus exactly one driving input — `input` (audio-to-video) or `input_tts` (text-to-video). The body may be JSON or `multipart/form-data` (upload `ref_image` / `input` as raw files).",
        "tags": [
          "Videos"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVideoRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "ref_image"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "default": "higgs-avatar"
                  },
                  "ref_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reference image file (PNG/JPEG/WEBP), or an http(s) URL string."
                  },
                  "input": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio-to-video driving-audio file (AAC/WAV/MP3/FLAC/OPUS), or an http(s) URL string. Provide exactly one of `input` / `input_tts`."
                  },
                  "input_tts": {
                    "type": "string",
                    "description": "Text-to-video: a JSON string of a speech request. Provide exactly one of `input` / `input_tts`."
                  },
                  "size": {
                    "type": "string",
                    "default": "640x640"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created Video object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. `invalid_image_format`, `invalid_size`, `audio_too_long`, `empty_input`, `input_too_long`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown avatar model (`model_not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Inline `ref_image` over the 10 MB cap (`payload_too_large`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Malformed body (e.g. neither or both of `input` / `input_tts`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited, or all replicas busy (`all_replicas_busy`); retry after `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/videos/{video_id}": {
      "get": {
        "operationId": "getVideo",
        "summary": "Retrieve a video",
        "description": "Retrieve the Video object (status / progress). Always JSON — the rendered MP4 is downloaded from `GET /v1/videos/{video_id}/content`.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "name": "video_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The video ID returned by `POST /v1/videos`."
          }
        ],
        "responses": {
          "200": {
            "description": "The Video object.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No video with that ID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/videos/{video_id}/content": {
      "get": {
        "operationId": "downloadVideoContent",
        "summary": "Download content",
        "description": "Download the rendered video. Returns the MP4 bytes (`variant=video`, the default). `404` until the video is `completed`.",
        "tags": [
          "Videos"
        ],
        "parameters": [
          {
            "name": "video_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The video ID."
          },
          {
            "name": "variant",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "video"
              ],
              "default": "video"
            },
            "description": "Which rendered asset to download. Only `video` (the MP4) is supported."
          }
        ],
        "responses": {
          "200": {
            "description": "The rendered MP4 bytes.",
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Unsupported `variant` (`invalid_variant`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such video, or its content is not ready yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/videos/stream": {
      "post": {
        "operationId": "streamVideo",
        "summary": "Create a video (streaming)",
        "description": "Same request body as `POST /v1/videos`, but the response body IS the live fragmented-MP4 (fMP4) byte stream — frames arrive as they are generated, so playback can start before the clip is complete. The video id rides back in the `X-Video-Id` header; the full MP4 is stored too, so a later `GET /v1/videos/{video_id}/content` works.",
        "tags": [
          "Videos"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVideoRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "ref_image"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "default": "higgs-avatar"
                  },
                  "ref_image": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reference image file (PNG/JPEG/WEBP), or an http(s) URL string."
                  },
                  "input": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio-to-video driving-audio file (AAC/WAV/MP3/FLAC/OPUS), or an http(s) URL string. Provide exactly one of `input` / `input_tts`."
                  },
                  "input_tts": {
                    "type": "string",
                    "description": "Text-to-video: a JSON string of a speech request. Provide exactly one of `input` / `input_tts`."
                  },
                  "size": {
                    "type": "string",
                    "default": "640x640"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The fragmented-MP4 (fMP4) byte stream.",
            "headers": {
              "X-Video-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "The video id, for a later retrieve / download."
              }
            },
            "content": {
              "video/mp4": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (same codes as `POST /v1/videos`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited, or all replicas busy (`all_replicas_busy`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/audio/voices": {
      "post": {
        "operationId": "createVoice",
        "summary": "Create a voice",
        "description": "Register a reusable reference voice for cloning. Identical audio re-registered under the same API key returns the existing voice. Pass the returned `voice` ID to the `voice` field of `POST /v1/audio/speech` instead of sending `ref_audio` on every request.",
        "tags": [
          "Audio"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVoiceRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "ref_audio",
                  "ref_text"
                ],
                "properties": {
                  "ref_audio": {
                    "type": "string",
                    "format": "binary",
                    "description": "Reference audio file. Max 10 MB, min 3.0 s."
                  },
                  "ref_text": {
                    "type": "string",
                    "minLength": 1,
                    "description": "Transcript of the reference audio."
                  },
                  "description": {
                    "type": "string",
                    "description": "Description for the voice."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created (or existing) voice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceObject"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listVoices",
        "summary": "List voices",
        "description": "List the reference voices registered under your API key.",
        "tags": [
          "Audio"
        ],
        "responses": {
          "200": {
            "description": "A list of voices.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceList"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/audio/voices/{voice}": {
      "get": {
        "operationId": "getVoice",
        "summary": "Get a voice",
        "description": "Fetch a single reference voice by ID.",
        "tags": [
          "Audio"
        ],
        "parameters": [
          {
            "name": "voice",
            "in": "path",
            "required": true,
            "description": "The voice ID, e.g. `voice_ab12...`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested voice.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VoiceObject"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No voice with that ID (`voice_not_found`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your Boson API key, sent as `Authorization: Bearer $BOSON_API_KEY`."
      }
    },
    "schemas": {
      "CreateSpeechRequest": {
        "type": "object",
        "required": [
          "input"
        ],
        "additionalProperties": false,
        "properties": {
          "input": {
            "type": "string",
            "minLength": 1,
            "maxLength": 5000,
            "description": "Text to convert to speech. May contain inline tags. Inputs longer than 5000 characters return a 400 `input_too_long`.",
            "example": "Hello, this is a test."
          },
          "model": {
            "type": "string",
            "default": "higgs-tts-3",
            "enum": [
              "higgs-tts-3"
            ],
            "description": "TTS model ID / public alias. Resolved to the served model server-side."
          },
          "voice": {
            "type": "string",
            "default": "default",
            "description": "Preset voice name or custom voice ID. Mutually exclusive with `ref_audio` / `ref_text` when explicitly provided."
          },
          "response_format": {
            "type": "string",
            "enum": [
              "mp3",
              "opus",
              "pcm",
              "wav",
              "aac",
              "flac"
            ],
            "default": "mp3",
            "description": "Output audio format. Streaming requires `pcm`."
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "If true, stream raw PCM chunks as they are decoded. Requires `response_format` to be `pcm`. Speed adjustment is not supported when streaming."
          },
          "ref_audio": {
            "type": "string",
            "nullable": true,
            "description": "Inline reference audio for one-off cloning: an http(s) URL, data URI, or base64-encoded raw audio bytes. Supported formats: AAC, WAV, MP3, FLAC, OPUS. Inline (base64 / data-URI) payloads: max 10 MB."
          },
          "ref_text": {
            "type": "string",
            "nullable": true,
            "description": "Recommended transcript of `ref_audio`."
          }
        }
      },
      "CreateVoiceRequest": {
        "type": "object",
        "required": [
          "ref_audio",
          "ref_text"
        ],
        "additionalProperties": false,
        "properties": {
          "ref_audio": {
            "type": "string",
            "description": "Reference audio: an http(s) URL, data URI, or base64. Max 10 MB, min 3.0 s."
          },
          "ref_text": {
            "type": "string",
            "minLength": 1,
            "description": "Transcript of the reference audio."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Description for the voice."
          }
        }
      },
      "VoiceObject": {
        "type": "object",
        "required": [
          "voice",
          "ref_text"
        ],
        "properties": {
          "voice": {
            "type": "string",
            "description": "Stable ID `voice_<sha256>`, deterministic per (API key, audio content)."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Description for the voice."
          },
          "created_at": {
            "type": "string",
            "nullable": true,
            "description": "ISO-8601 UTC timestamp."
          },
          "ref_text": {
            "type": "string",
            "description": "Transcript of the reference audio."
          }
        }
      },
      "VoiceListItem": {
        "type": "object",
        "required": [
          "voice"
        ],
        "properties": {
          "voice": {
            "type": "string",
            "description": "Stable ID `voice_<sha256>`."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Description for the voice."
          },
          "created_at": {
            "type": "string",
            "nullable": true,
            "description": "ISO-8601 UTC timestamp."
          }
        }
      },
      "VoiceList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "list"
            ],
            "default": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VoiceListItem"
            }
          }
        }
      },
      "CreateRealtimeClientSecretRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "expires_after": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "seconds": {
                "type": "integer",
                "minimum": 10,
                "maximum": 7200,
                "default": 600,
                "description": "Client-secret lifetime in seconds."
              }
            }
          }
        },
        "example": {
          "expires_after": {
            "seconds": 300
          }
        }
      },
      "RealtimeClientSecret": {
        "type": "object",
        "required": [
          "object",
          "value",
          "expires_at",
          "session"
        ],
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "realtime.client_secret"
            ]
          },
          "value": {
            "type": "string",
            "description": "Ephemeral key beginning with `bai-eph-`.",
            "example": "bai-eph-<hash>"
          },
          "expires_at": {
            "type": "integer",
            "description": "Expiration time as Unix seconds.",
            "example": 1712345678
          },
          "session": {
            "type": "object",
            "required": [
              "id",
              "object"
            ],
            "properties": {
              "id": {
                "type": "string",
                "description": "Realtime session identifier.",
                "example": "sess_ab12cd34"
              },
              "object": {
                "type": "string",
                "enum": [
                  "realtime.session"
                ]
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string",
                "description": "Human-readable error message."
              },
              "type": {
                "type": "string",
                "description": "Error category."
              }
            }
          }
        }
      },
      "CreateVideoRequest": {
        "type": "object",
        "required": [
          "ref_image"
        ],
        "additionalProperties": false,
        "description": "Provide a `ref_image` plus exactly one driving input: `input` (audio-to-video) or `input_tts` (text-to-video).",
        "properties": {
          "model": {
            "type": "string",
            "default": "higgs-avatar",
            "enum": [
              "higgs-avatar"
            ],
            "description": "Avatar model ID / public alias."
          },
          "ref_image": {
            "type": "string",
            "description": "Reference image (the face to animate): an http(s) URL, data URI, or base64-encoded raw image bytes. Supported formats: PNG, JPEG, WEBP. Inline (base64 / data-URI) payloads: max 10 MB."
          },
          "input": {
            "type": "string",
            "nullable": true,
            "description": "Audio-to-video: the driving speech audio as an http(s) URL, data URI, or base64-encoded raw audio bytes. Supported formats: AAC, WAV, MP3, FLAC, OPUS. Max duration: 60 s (it sets the output video length). Provide exactly one of `input` / `input_tts`."
          },
          "input_tts": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CreateSpeechRequest"
              }
            ],
            "nullable": true,
            "description": "Text-to-video: a speech request (the same body as `POST /v1/audio/speech`). The gateway synthesizes the voice and the avatar lip-syncs to it. The nested `stream` field is not supported. Provide exactly one of `input` / `input_tts`."
          },
          "size": {
            "type": "string",
            "enum": [
              "640x640",
              "640x480",
              "480x640"
            ],
            "default": "640x640",
            "description": "Output video size (WxH): square `640x640`, landscape `640x480`, or portrait `480x640`."
          }
        }
      },
      "Video": {
        "type": "object",
        "description": "A video generation job (the create / retrieve response).",
        "properties": {
          "id": {
            "type": "string",
            "description": "Video ID, e.g. `video_8a1f...`.",
            "example": "video_8a1f2c3d4e5f6a7b8c9d0e1f"
          },
          "object": {
            "type": "string",
            "enum": [
              "video"
            ],
            "default": "video"
          },
          "model": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "in_progress",
              "completed",
              "failed"
            ],
            "description": "Job status."
          },
          "progress": {
            "type": "integer",
            "description": "Completion percentage (0–100)."
          },
          "size": {
            "type": "string",
            "description": "Output size (WxH), e.g. `640x640`."
          },
          "created_at": {
            "type": "integer",
            "description": "Unix timestamp (seconds)."
          },
          "error": {
            "type": "string",
            "nullable": true,
            "description": "Error message when `status` is `failed`."
          }
        }
      }
    }
  }
}
