{
  "openapi": "3.1.0",
  "info": {
    "title": "Kontho REST API",
    "version": "1.0.0",
    "summary": "Bangla text to speech from your own server.",
    "description": "Turn Bangla text into audio (WAV or MP3) with Kontho voices, regional accents, or a voice you cloned on the website, and download the file into your own system. Authenticate with an application key made on the dashboard (https://kontho.net/app/api): `Authorization: Bearer kontho_sk_…`. Call it from your server, never from a web page (the API sends no CORS headers, so a browser cannot read the answers). Making audio costs credits (1 per second, HQ 2 per second) and needs one purchase of any package. Audio is kept for 30 days: download and store it. Human-readable guide: https://kontho.net/developers",
    "contact": {
      "name": "Kontho AI",
      "url": "https://kontho.net/developers"
    }
  },
  "servers": [
    {
      "url": "https://kontho.net/v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Text"
    },
    {
      "name": "Speech"
    }
  ],
  "paths": {
    "/balance": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getBalance",
        "summary": "Credits left",
        "description": "Free. Also a quick way to check that a key works.",
        "responses": {
          "200": {
            "description": "The balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                },
                "example": {
                  "credits": 596,
                  "approx_minutes_fast": 9,
                  "buy_url": "https://kontho.net/app/buy"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/voices": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "listVoices",
        "summary": "Voices, accents, styles and prices",
        "description": "Free. `builtin_voices[].id` (like `builtin:nila`) and `own_voices[].id` (a number) are what you pass as `voice_id`.",
        "responses": {
          "200": {
            "description": "The voices this account can use.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Voices"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/text/fix": {
      "post": {
        "tags": [
          "Text"
        ],
        "operationId": "fixText",
        "summary": "Prepare Bangla text for speech",
        "description": "Free. Writes numbers, dates, symbols and abbreviations out as Bangla words, fixes spelling, and can convert the text into a regional accent. Up to 2,000 characters. Counts toward the same hourly limit as the website's \"Fix text\" button.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FixRequest"
              },
              "example": {
                "text": "আমি ১০০ টাকা দিয়েছি।",
                "dialect": "standard"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The fixed text.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixResponse"
                },
                "example": {
                  "text": "আমি একশো টাকা দিয়েছি।"
                }
              }
            }
          },
          "400": {
            "description": "The text is missing or too long, or the accent is unknown. Codes: TEXT_EMPTY, TEXT_TOO_LONG, DIALECT_INVALID, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "The body is not JSON (415) or cannot be read (400). Codes: API_JSON_REQUIRED, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "description": "The voice service had a problem or is busy. Nothing is charged. Try again a little later. Codes: UPSTREAM, UPSTREAM_BUSY, UPSTREAM_TIMEOUT, QUOTA, QUOTA_DAILY, CONTENT_BLOCKED, SERVER_ERROR.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/speech/estimate": {
      "post": {
        "tags": [
          "Speech"
        ],
        "operationId": "estimateSpeech",
        "summary": "What a text would cost",
        "description": "Free. About 13 characters make one second of audio; Fast costs 1 credit per second, HQ 2.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateRequest"
              },
              "example": {
                "text": "আমি বাংলায় কথা বলি।",
                "quality": "fast"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The estimate.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Estimate"
                },
                "example": {
                  "credits_needed": 2,
                  "approx_seconds": 2,
                  "credits": 596,
                  "enough": true,
                  "quality": "fast"
                }
              }
            }
          },
          "400": {
            "description": "The text is missing or too long, or the quality is unknown. Codes: TEXT_EMPTY, TEXT_TOO_LONG, QUALITY_INVALID, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "The body is not JSON (415) or cannot be read (400). Codes: API_JSON_REQUIRED, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/speech": {
      "post": {
        "tags": [
          "Speech"
        ],
        "operationId": "createSpeech",
        "summary": "Make audio",
        "description": "Makes the audio and charges the credits (the real length, 1 per second, HQ 2). Needs one purchase of any package. A text of 5,000 characters can take several minutes: send at most about 2,500 characters per call and join the WAV files yourself. Send an `Idempotency-Key` header so a retry after a timeout returns the first answer instead of charging again (a replay answers 200 with `Idempotent-Replayed: true`). Send `Accept: audio/wav` or `Accept: audio/mpeg` to get the audio file in this response instead of JSON (the numbers come in `X-Kontho-*` headers). Set `format` to `mp3` to get an MP3 (128 kbps, mono) instead of the WAV: `audio_url` and `download_url` then point at the MP3, which is made the first time it is asked for; it costs no extra credits. `format` wins over `Accept`, and it is part of the request for `Idempotency-Key`.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "1 to 64 characters: letters, digits, - and _. Use a new key for each different audio; the same key with the same request returns the first answer for 24 hours.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{1,64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpeechRequest"
              },
              "example": {
                "text": "আমি বাংলায় কথা বলি।",
                "voice_id": "builtin:nila",
                "style": "normal",
                "dialect": "standard",
                "quality": "fast"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The audio was made and charged. JSON by default; with `Accept: audio/wav` or `audio/mpeg` the body is the audio file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Speech"
                },
                "example": {
                  "id": 123,
                  "object": "speech",
                  "seconds": 3.1,
                  "credits_charged": 4,
                  "credits_left": 596,
                  "quality": "fast",
                  "dialect": "standard",
                  "style": "normal",
                  "spoken_text": "আমি বাংলায় কথা বলি।",
                  "created_at": "2026-10-31T10:00:00.000Z",
                  "expires_at": "2026-11-30T10:00:00.000Z",
                  "audio_url": "https://kontho.net/v1/speech/123/audio",
                  "download_url": "https://kontho.net/api/audio/123/Ab3dEfGh1jKlMnOpQrStUvWxYz0123456789AbCdEfG"
                }
              },
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "headers": {
              "X-Kontho-Speech-Id": {
                "schema": {
                  "type": "string"
                },
                "description": "Only when the file itself is returned (Accept: audio/wav or audio/mpeg)."
              },
              "X-Kontho-Seconds": {
                "schema": {
                  "type": "string"
                },
                "description": "Only when the file itself is returned (Accept: audio/wav or audio/mpeg)."
              },
              "X-Kontho-Credits-Charged": {
                "schema": {
                  "type": "string"
                },
                "description": "Only when the file itself is returned (Accept: audio/wav or audio/mpeg)."
              },
              "X-Kontho-Credits-Left": {
                "schema": {
                  "type": "string"
                },
                "description": "Only when the file itself is returned (Accept: audio/wav or audio/mpeg)."
              }
            }
          },
          "200": {
            "description": "A replay: this Idempotency-Key already made this audio. Nothing is charged again.",
            "headers": {
              "Idempotent-Replayed": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Speech"
                },
                "example": {
                  "id": 123,
                  "object": "speech",
                  "seconds": 3.1,
                  "credits_charged": 4,
                  "credits_left": 596,
                  "quality": "fast",
                  "dialect": "standard",
                  "style": "normal",
                  "spoken_text": "আমি বাংলায় কথা বলি।",
                  "created_at": "2026-10-31T10:00:00.000Z",
                  "expires_at": "2026-11-30T10:00:00.000Z",
                  "audio_url": "https://kontho.net/v1/speech/123/audio",
                  "download_url": "https://kontho.net/api/audio/123/Ab3dEfGh1jKlMnOpQrStUvWxYz0123456789AbCdEfG"
                }
              },
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Something in the request is not valid. Nothing is charged. Codes: TEXT_EMPTY, TEXT_TOO_LONG, STYLE_INVALID, QUALITY_INVALID, DIALECT_INVALID, SCRIPT_BLOCKED, FORMAT_INVALID, IDEMPOTENCY_KEY_INVALID, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Not enough credits. Nothing is charged. Codes: INSUFFICIENT_CREDITS.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API needs one purchase of any package. Codes: API_NEEDS_PURCHASE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "The voice was not found. Codes: VOICE_NOT_FOUND.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running. Send the same request again in a little while. Codes: IDEMPOTENCY_IN_PROGRESS.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "The body is not JSON (415) or cannot be read (400). Codes: API_JSON_REQUIRED, BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "This Idempotency-Key was already used for a different request. Codes: IDEMPOTENCY_KEY_REUSED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "default": {
            "description": "The voice service had a problem or is busy. Nothing is charged. Try again a little later. Codes: UPSTREAM, UPSTREAM_BUSY, UPSTREAM_TIMEOUT, QUOTA, QUOTA_DAILY, CONTENT_BLOCKED, SERVER_ERROR.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Speech"
        ],
        "operationId": "listSpeech",
        "summary": "Audio made recently",
        "description": "Free. The last audio of this account (made on the website, in a chatbot or through the API), newest first. `spoken_text` is cut to 160 characters here; get one audio for the whole text. The links in a list are WAV links; add `?format=mp3` to a link, or ask for one audio with `?format=mp3`, to get the MP3.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1 to 50, default 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "An audio id: only older audio is returned. Use the last id of the previous page.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of audio.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeechList"
                }
              }
            }
          },
          "400": {
            "description": "`before` is not a number. Codes: BAD_JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/speech/{id}": {
      "get": {
        "tags": [
          "Speech"
        ],
        "operationId": "getSpeech",
        "summary": "One audio",
        "description": "Free. The full text and a login-free `download_url` (valid until the audio expires). An audio of another account answers 404.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Which file `audio_url` and `download_url` give: `wav` (default) or `mp3`.",
            "schema": {
              "type": "string",
              "enum": [
                "wav",
                "mp3"
              ],
              "default": "wav"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The audio.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Speech"
                },
                "example": {
                  "id": 123,
                  "object": "speech",
                  "seconds": 3.1,
                  "credits_charged": 4,
                  "credits_left": 596,
                  "quality": "fast",
                  "dialect": "standard",
                  "style": "normal",
                  "spoken_text": "আমি বাংলায় কথা বলি।",
                  "created_at": "2026-10-31T10:00:00.000Z",
                  "expires_at": "2026-11-30T10:00:00.000Z",
                  "audio_url": "https://kontho.net/v1/speech/123/audio",
                  "download_url": "https://kontho.net/api/audio/123/Ab3dEfGh1jKlMnOpQrStUvWxYz0123456789AbCdEfG"
                }
              }
            }
          },
          "400": {
            "description": "`format` is not `wav` or `mp3`. Codes: FORMAT_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such audio in this account. Codes: NOT_FOUND.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/speech/{id}/audio": {
      "get": {
        "tags": [
          "Speech"
        ],
        "operationId": "downloadSpeech",
        "summary": "Download the audio (WAV or MP3)",
        "description": "Free. The WAV file (24 kHz, mono, 16-bit), or with `?format=mp3` an MP3 (128 kbps, mono; made the first time it is asked for, then kept). Range requests work. Needs one purchase, like making audio. After 30 days the files are deleted and this answers 410. Audio from a long script made on the website has no MP3.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`wav` (default) or `mp3`.",
            "schema": {
              "type": "string",
              "enum": [
                "wav",
                "mp3"
              ],
              "default": "wav"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The audio file.",
            "content": {
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "206": {
            "description": "Part of the file (a Range request).",
            "content": {
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "`format` is not `wav` or `mp3` (FORMAT_INVALID), or this audio has no MP3: it comes from a long script (FORMAT_UNAVAILABLE). Codes: FORMAT_INVALID, FORMAT_UNAVAILABLE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "The key is missing, wrong, revoked, or the account is closed. Codes: API_KEY_REQUIRED, API_KEY_INVALID.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The API needs one purchase of any package. Codes: API_NEEDS_PURCHASE.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such audio in this account. Codes: NOT_FOUND.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "The file was deleted after 30 days. Codes: AUDIO_EXPIRED.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests. Wait for Retry-After seconds. Codes: RATE_LIMITED.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "string"
                },
                "description": "Seconds to wait (60)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An application key from the dashboard tab “API ও MCP”, like `kontho_sk_…`. Shown once when made; revoke it there any time. Chatbot (OAuth) connections do not work here."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "message_bn",
              "status"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "A stable code like INSUFFICIENT_CREDITS. Use this in your code."
              },
              "message": {
                "type": "string",
                "description": "English text for people. Do not parse it."
              },
              "message_bn": {
                "type": "string",
                "description": "The same in Bangla."
              },
              "status": {
                "type": "integer",
                "description": "The HTTP status."
              },
              "ref": {
                "type": "integer",
                "description": "A reference number to give support, when the error was logged."
              }
            }
          }
        }
      },
      "Balance": {
        "type": "object",
        "required": [
          "credits",
          "approx_minutes_fast",
          "buy_url"
        ],
        "properties": {
          "credits": {
            "type": "integer"
          },
          "approx_minutes_fast": {
            "type": "integer",
            "description": "Minutes of Fast audio the credits make."
          },
          "buy_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Voices": {
        "type": "object",
        "properties": {
          "own_voices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          },
          "builtin_voices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "examples": [
                    "builtin:nila"
                  ]
                },
                "name": {
                  "type": "string"
                },
                "name_bn": {
                  "type": "string"
                },
                "gender": {
                  "type": "string"
                },
                "dialect": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "dialects": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "label_en": {
                  "type": "string"
                },
                "label_bn": {
                  "type": "string"
                }
              }
            }
          },
          "styles": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "label_en": {
                  "type": "string"
                }
              }
            }
          },
          "quality": {
            "type": "object",
            "properties": {
              "fast": {
                "type": "object",
                "properties": {
                  "credits_per_second": {
                    "type": "integer"
                  }
                }
              },
              "hq": {
                "type": "object",
                "properties": {
                  "credits_per_second": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      },
      "FixRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 2000
          },
          "dialect": {
            "type": "string",
            "enum": [
              "standard",
              "noakhali",
              "barishal",
              "rajshahi",
              "sylhet",
              "chittagong",
              "puran_dhaka",
              "comilla",
              "mymensingh",
              "rangpur"
            ],
            "default": "standard"
          }
        }
      },
      "FixResponse": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string"
          },
          "warning": {
            "type": "string",
            "description": "Sometimes: something in the text may not be spoken as expected."
          }
        }
      },
      "EstimateRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 5000
          },
          "quality": {
            "type": "string",
            "enum": [
              "fast",
              "hq"
            ],
            "default": "fast"
          }
        }
      },
      "Estimate": {
        "type": "object",
        "properties": {
          "credits_needed": {
            "type": "integer"
          },
          "approx_seconds": {
            "type": "integer"
          },
          "credits": {
            "type": "integer"
          },
          "enough": {
            "type": "boolean"
          },
          "quality": {
            "type": "string",
            "enum": [
              "fast",
              "hq"
            ]
          }
        }
      },
      "SpeechRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "maxLength": 5000,
            "description": "The Bangla text to speak. With `fix_text: true` at most 2,000 characters."
          },
          "voice_id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ],
            "default": "builtin:nila",
            "description": "`builtin:<name>` or the id of a voice you cloned (from GET /voices)."
          },
          "style": {
            "type": "string",
            "enum": [
              "normal",
              "news",
              "story",
              "ad",
              "calm",
              "teach",
              "romantic"
            ],
            "default": "normal"
          },
          "dialect": {
            "type": "string",
            "enum": [
              "standard",
              "noakhali",
              "barishal",
              "rajshahi",
              "sylhet",
              "chittagong",
              "puran_dhaka",
              "comilla",
              "mymensingh",
              "rangpur"
            ],
            "default": "standard",
            "description": "The accent."
          },
          "quality": {
            "type": "string",
            "enum": [
              "fast",
              "hq"
            ],
            "default": "fast"
          },
          "fix_text": {
            "type": "boolean",
            "default": false,
            "description": "Prepare the text for speech first (free), as POST /text/fix does."
          },
          "format": {
            "type": "string",
            "enum": [
              "wav",
              "mp3"
            ],
            "default": "wav",
            "description": "`mp3` gives an MP3 (128 kbps, mono) instead of the WAV: `audio_url` and `download_url` point at it. Wins over `Accept`."
          }
        }
      },
      "Speech": {
        "type": "object",
        "required": [
          "id",
          "object",
          "format",
          "seconds",
          "credits_charged",
          "spoken_text",
          "created_at",
          "expires_at",
          "audio_url"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "enum": [
              "speech"
            ]
          },
          "seconds": {
            "type": "number"
          },
          "credits_charged": {
            "type": "integer"
          },
          "credits_left": {
            "type": "integer",
            "description": "Only in the answer to POST /speech."
          },
          "quality": {
            "type": "string",
            "enum": [
              "fast",
              "hq"
            ]
          },
          "dialect": {
            "type": "string"
          },
          "style": {
            "type": "string"
          },
          "spoken_text": {
            "type": "string",
            "description": "The exact words in the audio (use it for subtitles)."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "audio_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Needs your key: GET it with the Authorization header. null once the file expired."
          },
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "Needs no key: anyone with this link can download until the audio expires. Not in lists."
          },
          "expired": {
            "type": "boolean",
            "description": "true when the file was deleted."
          },
          "format": {
            "type": "string",
            "enum": [
              "wav",
              "mp3"
            ],
            "description": "Which file `audio_url` and `download_url` give."
          }
        }
      },
      "SpeechList": {
        "type": "object",
        "required": [
          "data",
          "has_more"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speech"
            }
          },
          "has_more": {
            "type": "boolean"
          }
        }
      }
    }
  }
}
