# Karaoke subtitles

- Human page: https://happytails.ai/en/api/tools/karaoke-subtitles/
- Markdown: https://happytails.ai/en/api/tools/karaoke-subtitles.md
- Structured JSON: https://happytails.ai/agents/en/api/tools/karaoke-subtitles/index.json
- Visibility: public

## Page guide

API reference

Create word-timed karaoke subtitles from matching speech and text.

POST

/api/v1/tools/karaoke-subtitles/run

Base URL: https://happytails.ai · public API not connected

## Overview

Local Whisper forced alignment. English, up to one minute and 5,000 transcript characters. Review word timing; singing and overlapping voices may align poorly.

All API requests process supplied data on the server. [File handling and privacy](https://happytails.ai/en/api/#files).

## Request parameters

Send a JSON object. Unknown properties are rejected. Omitted options use the defaults below; enter numbers and booleans as JSON values, not quoted text.

No text input is needed. Use the settings and files below.

### Files

Accepted formats: `.wav,.mp3,.m4a,.flac,.mp4,.webm`. Up to 1 file(s), totaling 20 MiB decoded.

Each `files` entry requires `name` and padded `base64`. Optional `mime` describes the content; optional `bytes` must equal its decoded length. Filenames cannot contain paths. File URLs are not accepted. See [uploading and saving files](https://happytails.ai/en/api/#files).

### Options

#### `options.transcript`

Type: string

Matching English transcript or lyrics

Default: `""`

## Success response

HTTP 200 returns `tool` and `result`. Text is in `result.text`; parsed JSON may also appear in `result.data`. Generated files are in `result.files` with `name`, `mime`, `bytes` and `base64`. Decode the bytes before saving. Empty file arrays and null text are valid for operations returning another result type.

### Complete output schema

```json
{
  "type": "object",
  "required": [
    "tool",
    "result"
  ],
  "properties": {
    "tool": {
      "type": "string"
    },
    "result": {
      "type": "object",
      "required": [
        "text",
        "files"
      ],
      "properties": {
        "text": {
          "type": [
            "string",
            "null"
          ]
        },
        "data": {
          "description": "Parsed JSON when the textual result is JSON."
        },
        "name": {
          "type": "string"
        },
        "mime": {
          "type": "string"
        },
        "files": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "name",
              "mime",
              "bytes",
              "base64"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "mime": {
                "type": "string"
              },
              "bytes": {
                "type": "integer"
              },
              "base64": {
                "type": "string",
                "contentEncoding": "base64"
              }
            }
          }
        }
      }
    }
  }
}
```

## Limits and failures

Limits below are enforced by this endpoint. Additional format, page, duration and model limits in the behavior notes also apply. Browser UI limits can differ from API limits.

| Field | Value |
| --- | --- |
| `request_bytes` | 31457280 |
| `input_characters` | 1000000 |
| `files_bytes` | 20971520 |
| `max_files` | 1 |
| `timeout_seconds` | 90 |

Invalid requests return an `error` object with `code` and `message`. Read [HTTP statuses, retries, timeouts and concurrency](https://happytails.ai/en/api/#limits). Execution is synchronous and results are returned in the response.

## Complete request schema

### Expand the JSON schema

```json
{
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "input": {
      "type": "string",
      "maxLength": 1000000,
      "default": "",
      "description": "Plain text input. File tools use files instead unless otherwise documented."
    },
    "options": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "transcript": {
          "type": "string",
          "description": "Matching English transcript or lyrics",
          "default": ""
        }
      }
    },
    "files": {
      "type": "array",
      "maxItems": 1,
      "items": {
        "type": "object",
        "required": [
          "name",
          "base64"
        ],
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 200,
            "description": "Filename only, no path."
          },
          "mime": {
            "type": "string",
            "maxLength": 150
          },
          "bytes": {
            "type": "integer",
            "minimum": 0,
            "description": "Optional decoded byte count; must match content if supplied."
          },
          "base64": {
            "type": "string",
            "contentEncoding": "base64",
            "description": "File bytes as padded base64. Use the tool-specific limits.files_bytes value for the total decoded input size."
          }
        }
      }
    }
  }
}
```

For browser automation, use the central [WebMCP guidance](https://happytails.ai/en/api/#browser-agents) and discover the tools actually exposed by the browser.

Request example

### Python

```python
import json
from urllib.request import Request, urlopen
import base64
from pathlib import Path

source = Path("input.wav")

payload = json.loads('{"options": {"transcript": ""}}')
payload["files"] = [{
    "name": source.name,
    "base64": base64.b64encode(source.read_bytes()).decode("ascii")
}]

request = Request(
    "https://happytails.ai/api/v1/tools/karaoke-subtitles/run",
    data=json.dumps(payload).encode(),
    headers={"Content-Type": "application/json"},
)
with urlopen(request, timeout=200) as response:
    result = json.load(response)
    print(result)
```

### JavaScript

```javascript
import { readFile } from "node:fs/promises";

const filename = "input.wav";
const payload = {
  "options": {
    "transcript": ""
  }
};
payload.files = [{
  name: filename,
  base64: (await readFile(filename)).toString("base64")
}];

const response = await fetch(
  "https://happytails.ai/api/v1/tools/karaoke-subtitles/run",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload)
  }
);
const data = await response.json();
if (!response.ok) throw new Error(data.error.message);
console.log(data.result);
```

### cURL

```bash
# Save the JSON body as request.json first.
curl https://happytails.ai/api/v1/tools/karaoke-subtitles/run \
  -H "Content-Type: application/json" \
  --data-binary @request.json
```

### JSON

```json
{
  "options": {
    "transcript": ""
  },
  "files": [
    {
      "name": "input.wav",
      "base64": "BASE64_FILE_BYTES"
    }
  ]
}
```

Python and JavaScript read your local file and encode it as Base64. Replace the input filename and API origin.

200 OK · response structure

### JSON

```json
{
  "tool": "karaoke-subtitles",
  "result": {
    "text": null,
    "files": [
      {
        "name": "result",
        "mime": "application/octet-stream",
        "bytes": 0,
        "base64": "BASE64_OUTPUT_BYTES"
      }
    ]
  }
}
```

Illustrative envelope. Actual text, filename, MIME type and bytes depend on the result. See the complete output schema.

400 Bad Request

### JSON

```json
{
  "error": {
    "code": "INVALID_INPUT",
    "message": "Unknown request property. See the tool input schema."
  }
}
```
