Speech to Text API
Upload one audio file and receive a completed transcript as JSON or plain text. The multipart fields and response use a familiar OpenAI transcription shape, but the endpoint is different, so changing only an OpenAI SDK Base URL is not supported.
API overview
| Item | Value |
|---|---|
| Base URL | https://api.kitschlabs.com |
| Endpoint | POST /v1/speech-to-text |
| Authentication | Authorization: Bearer <API_KEY> or xi-api-key: <API_KEY> |
| Request | multipart/form-data |
| Model | kitsch-stt-v1 |
| Maximum file size | 100 MiB |
| Default response | JSON |
Speech to Text is enabled by default for every authenticated account.
How do I transcribe a file?
- cURL
- Python
- JavaScript
curl --request POST \
"https://api.kitschlabs.com/v1/speech-to-text" \
--header "Authorization: Bearer <API_KEY>" \
--form "file=@speech.wav" \
--form "model=kitsch-stt-v1" \
--form "language=en" \
--form "response_format=json"
import os
import requests
with open("speech.wav", "rb") as audio:
response = requests.post(
"https://api.kitschlabs.com/v1/speech-to-text",
headers={"Authorization": f"Bearer {os.environ['KITSCH_API_KEY']}"},
data={
"model": "kitsch-stt-v1",
"language": "en",
"response_format": "json",
},
files={"file": audio},
timeout=120,
)
response.raise_for_status()
print(response.json()["text"])
import { readFile } from "node:fs/promises";
const form = new FormData();
form.append("file", new Blob([await readFile("speech.wav")]), "speech.wav");
form.append("model", "kitsch-stt-v1");
form.append("language", "en");
form.append("response_format", "json");
const response = await fetch("https://api.kitschlabs.com/v1/speech-to-text", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.KITSCH_API_KEY}` },
body: form,
});
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`);
}
console.log((await response.json()).text);
What fields can I send?
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | Audio file to transcribe, up to 100 MiB |
model | string | Yes | kitsch-stt-v1 |
language | string | No | Expected ISO 639-1 language code, such as ko, en, or ja |
prompt | string | No | Short hint for proper nouns or context |
response_format | string | No | json (default) or text |
stream | boolean | No | Only false is supported |
kitsch_options | JSON string | No | Advanced recognition options |
temperature, stream=true, other model IDs, and unsupported response formats
return an error. To send audio as it is produced, use the
Streaming API.
Advanced options
Send kitsch_options as a JSON string. Supported keys are:
language_hints,language_hints_strictenable_speaker_diarizationenable_language_identificationcontexttranslation
--form 'kitsch_options={"language_hints":["ko","en"],"enable_speaker_diarization":true}'
Unknown keys return an error.
What does the response look like?
Response with response_format=json:
{
"text": "Hello.",
"usage": {
"type": "duration",
"seconds": 1.25
}
}
With response_format=text, the API returns UTF-8 plain text. Record the
x-kitsch-request-id response header for support and incident investigation.
How is usage billed?
Successful requests are billed at 0.1 credits per started second of input audio. For example, 4.2 and 5.0 seconds each cost 0.5 credits, while 5.1 seconds costs 0.6 credits. Failed requests and requests rejected during input validation are not charged.
How should I handle errors?
The error body includes error.message, error.type, error.param, and
error.code.
{
"error": {
"message": "The uploaded file is too large.",
"type": "invalid_request_error",
"param": "file",
"code": "file_too_large"
}
}
| Status | Meaning | Recommended action |
|---|---|---|
400 or 422 | Invalid file, model, or option | Check the fields and audio file |
401 | Missing or invalid API key | Check the authentication header |
402 | Insufficient credits | Check the balance and billing status |
413 | File exceeds the size limit | Reduce the file to 100 MiB or less |
429 | Request or processing capacity limit | Follow Retry-After and apply backoff |
503 | Temporarily unavailable | Record the request ID and retry selectively |