Kotoba Speech-to-Text API: Pricing, Documentation
Kotoba Speech-to-Text API provides a highly efficient and accurate solution for converting spoken language into precise written text in real time. Designed to handle diverse acoustic environments, varying accents, and complex vocabularies, this advanced tool seamlessly processes audio inputs to deliver reliable transcriptions for integration into modern applications. By leveraging state-of-the-art voice recognition technology, it enables developers to build smarter communication interfaces, automate documentation workflows, and enhance accessibility features across a wide range of software ecosystems without sacrificing speed or performance.

Models Version
Get 10% Cashback on Your First Payment (up to $500)
Add funds and get 10% cashback on your first payment (up to $500).
Kotoba Speech-to-Text API Documentation
Transcribe speech with Kotoba Speech-to-Text, tuned for Japanese and other East Asian languages: send one audio file of 2 minutes or less in audio_url and its language in language. Add with_timestamps for word timings, diarization to tell speakers apart and keywords to suggest the spelling of names and terms. Asynchronous: submit returns a request_id; poll the status endpoint until the request is COMPLETED, then read the transcript from output.text.
POST https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-textAuthentication
All requests require an API key passed via header.
| Header | Type | Required | Description |
|---|---|---|---|
| Ocp-Apim-Subscription-Key | string | Yes | Your API subscription key |
Speech to Text - Kotoba Speech-to-Text
Request Code
POST https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text
Content-Type: application/json
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en"
}import requests
url = "https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text"
headers = {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
}
data = {
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en"
}
resp = requests.post(url, json=data, headers=headers)
print(resp.json())const res = await fetch("https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Ocp-Apim-Subscription-Key": "YOUR_SUBSCRIPTION_KEY"
},
body: JSON.stringify({
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en"
})
});
console.log(await res.json());curl -X POST 'https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "language": "en"}'Output
{
"request_id": "kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Webhook (Optional)
Instead of polling, you can receive a Webhook callback when the request reaches a terminal state. Provide a Webhook URL via header on the submit request.
| Header | Required | Description |
|---|---|---|
| X-Webhook-URL | To enable | HTTPS URL to receive the Webhook callback. |
| X-Webhook-Mode | No | terminal (default, one callback on COMPLETED/ERROR) or sync (per-poll callbacks). |
Example: enable Webhook
curl -X POST 'https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text' \
-H 'Content-Type: application/json' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY' \
-H 'X-Webhook-URL: https://your-server.com/webhook' \
--data-raw '{"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3", "language": "en"}'Callback Payload (success)
{
"request_id": "kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "kotoba-stt",
"error": null,
"output": {
"media_url": [
"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json"
],
"media_type": "application/json",
"text": "The transcript of the audio.",
"words": [
{
"text": "The",
"start": null,
"end": null,
"type": "word",
"speaker_id": null
}
],
"language_code": "en",
"language_probability": 0.98,
"audio_duration_secs": 17.03
},
"created_at": "2026-10-09T10:04:54.387Z",
"completed_at": "2026-10-09 10:06:21"
}Failure callback shape
{
"request_id": "kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "ERROR",
"model_id": "kotoba-stt",
"error": "Description of the failure"
}Delivery semantics
- terminal mode: one Webhook callback when the request is COMPLETED or ERROR.
- sync mode: a Webhook callback on every poll while the request is processing (status
PROCESSING), plus the final COMPLETED/ERROR callback. - Callbacks are idempotent on
request_id— de-duplicate on it. - Respond
200within a few seconds; the Webhook endpoint must be HTTPS.
Request Parameters
| Parameter | Required | Type | Default | Allowed values / range | Description |
|---|---|---|---|---|---|
audio_url | Yes | string | — | A publicly reachable https URL (recommended) or a base64 data URI of an audio file of 2 minutes or less, for example MP3, WAV or M4A | The speech to transcribe. A file that states a longer length is refused at submit. |
language | Yes | string | — | ja, en, ko, zh, es, zh-hk, zh-tw | The language spoken in the audio. The model does not detect it. |
with_timestamps | No | boolean | false | true, false | Return a start and end time for each word in output.words. |
diarization | No | boolean | false | true, false | Attribute each word to a speaker (speaker_id). Word times stay empty unless with_timestamps is also true. |
keywords | No | array | — | Up to 1000 terms of at most 64 characters each | Names or product words whose spelling the transcript should prefer. |
kana | No | boolean | false | true, false | Write personal and place names in katakana (Japanese). |
Good to know
- Each request returns one transcript.
batch_size,num_images,number_of_images,nandcountare rejected — send one request per transcript. - This API has no length setting: the transcript covers the whole audio file (2 minutes or less).
duration,seconds,num_frames,frames_per_secondandmusic_length_msare rejected. - Send every field at the top level of the JSON body;
parameters,contentandtextare rejected. - Send one audio file as
audio_url: a publicly reachablehttpsURL (recommended) or a base64 data URI, 2 minutes or less. A file that states a longer length is refused at submit, with nothing charged; a file that cannot be downloaded fails the request withstatus: "ERROR", and nothing is charged. languageis required:ja,en,ko,zh,es,zh-hkorzh-tw. The model does not detect the language, so send the one spoken in the audio.keywordstakes at most 1000 terms of at most 64 characters each; a longer term fails the request withstatus: "ERROR", and nothing is charged.- Audio without speech returns an empty
output.text; the request is still billed for the length of the audio. audio_urlsis rejected (send one file per request, asaudio_url).promptis rejected (usekeywordsto suggest the spelling of names and terms).language_codeis rejected (send the language aslanguage).- Use the JSON types shown:
audio_urlandlanguageare strings,with_timestamps,diarizationandkanaaretrueorfalse(not"true"), andkeywordsis a list of strings. - Omit a field instead of sending
null. - Results are always returned as a URL in
output.media_url;sync_modeis accepted only asfalse. - Webhooks are set with the
X-Webhook-URL/X-Webhook-Modeheaders;webhook_url,webhook_modeandcallback_urlin the JSON body are rejected. streamis not supported: the result is delivered when the job completes.- Options this API does not offer are rejected:
inputandmodel.
Timestamps, Speakers and Keywords
- With
with_timestampstrue, each entry ofoutput.wordscarriesstartandendin seconds. - With
diarizationtrue, each word carries aspeaker_id; sendwith_timestampstoo if you need the times. output.wordsholds words, the spaces between them (typespacing) and sound events such as laughter (typeaudio_event).keywordsonly suggests spellings: names, brands and product words the transcript should prefer. It does not change the amount billed.
Example: word timings and speakers
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"with_timestamps": true,
"diarization": true
}Example: suggest spellings
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en",
"keywords": [
"Pixazo",
"Kotoba"
]
}Example Request
{
"audio_url": "https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3",
"language": "en"
}Example Response
{
"request_id": "kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "QUEUED",
"polling_url": "https://gateway.pixazo.ai/v2/requests/status/kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Request Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| Ocp-Apim-Subscription-Key | Yes | Your API subscription key. |
| X-Webhook-URL | No | Enable Webhook callbacks (see Webhook section). |
| X-Webhook-Mode | No | terminal (default) or sync (see Webhook section). |
Response Handling
| Status Code | Meaning |
|---|---|
| 202 | Accepted — request queued; returns request_id and polling_url. |
| 400 | Invalid request — a required field is missing, a value has the wrong type, is too long, out of range or not one of the allowed values, or a field this operation does not accept was sent. The message says what to fix. |
| 401 | Unauthorized — missing or invalid subscription key. |
| 402 | Insufficient balance for the hold this request needs. |
| 429 | Too many requests. |
| 500 | Internal server error. |
Parameter problems are caught when you submit and returned as a 400, before any hold is placed on your balance. Problems that need the model to run are reported through the status endpoint as status: "ERROR", with a message in error saying what went wrong. Failed requests are not billed — the hold is released in full.
| Condition | How it surfaces |
|---|---|
| Missing or invalid subscription key | synchronous 401 |
| Balance too low for the hold | synchronous 402 |
Missing or empty audio_url, audio_url not a string | synchronous 400 |
Missing or empty language, language not a string | synchronous 400 |
keywords not a list, or more than 1000 items | synchronous 400 |
with_timestamps or diarization or kana not true or false — for example the string "true" | synchronous 400 |
sync_mode set to anything other than false (results are always returned as a URL in output.media_url) | synchronous 400 |
audio_urls (send one file per request, as audio_url) | synchronous 400 |
prompt (use keywords to suggest the spelling of names and terms) | synchronous 400 |
language_code (send the language as language) | synchronous 400 |
batch_size, num_images, number_of_images, n, count (one transcript per request) | synchronous 400 |
duration, seconds, num_frames, frames_per_second, music_length_ms (the length is the audio file's own) | synchronous 400 |
parameters, content, text (send the fields at the top level of the JSON body) | synchronous 400 |
webhook_url, webhook_mode, callback_url in the JSON body (use the X-Webhook-URL / X-Webhook-Mode headers) | synchronous 400 |
stream (the result is delivered when the job completes) | synchronous 400 |
input, model (not accepted by this operation) | synchronous 400 |
An audio_url whose file states a length over 2 minutes (the response names the measured length) | synchronous 400 |
| An audio file that cannot be downloaded, is larger than 32 MB, or that the model cannot decode | status: "ERROR" |
| Audio longer than 2 minutes whose file did not state its length | status: "ERROR" |
A keywords term longer than 64 characters | status: "ERROR" |
Example error responses
A refused request returns error, a message that joins every problem found, and the same problems one by one in violations.
Missing audio_url (synchronous 400)
{
"error": "Invalid request parameters",
"message": "'audio_url' is required",
"violations": [
"'audio_url' is required"
]
}A language that is not offered (synchronous 400)
{
"error": "Invalid request parameters",
"message": "'language' must be one of: \"ja\", \"en\", \"ko\", \"zh\", \"es\", \"zh-hk\", \"zh-tw\" (got \"fr\")",
"violations": [
"'language' must be one of: \"ja\", \"en\", \"ko\", \"zh\", \"es\", \"zh-hk\", \"zh-tw\" (got \"fr\")"
]
}More than one file per request (synchronous 400)
{
"error": "Invalid request parameters",
"message": "'audio_urls' must be one of: (got [\"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3\",\"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3\"]); 'audio_urls' is not accepted: each request transcribes one audio file, as 'audio_url'.",
"violations": [
"'audio_urls' must be one of: (got [\"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3\",\"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/doc-assets/audio/speech-17s.mp3\"])",
"'audio_urls' is not accepted: each request transcribes one audio file, as 'audio_url'."
]
}with_timestamps as a string (synchronous 400)
{
"error": "Invalid request parameters",
"message": "'with_timestamps' must be boolean (got string)",
"violations": [
"'with_timestamps' must be boolean (got string)"
]
}A length setting (synchronous 400)
{
"error": "Invalid request parameters",
"message": "'duration' must be one of: (got 10); 'duration' is not accepted: the length is the audio file's own (2 minutes or less).",
"violations": [
"'duration' must be one of: (got 10)",
"'duration' is not accepted: the length is the audio file's own (2 minutes or less)."
]
}Retrieving Results
Poll the status endpoint with the request_id from the submit response until status is COMPLETED or ERROR, then read the transcript in output.text (the same JSON is stored as a file at output.media_url[0]). Treat any status other than QUEUED, PROCESSING or COMPLETED as a failure.
Endpoint
GET https://gateway.pixazo.ai/v2/requests/status/{request_id}
Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEYcURL example
curl 'https://gateway.pixazo.ai/v2/requests/status/kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' \
-H 'Ocp-Apim-Subscription-Key: YOUR_SUBSCRIPTION_KEY'Completed response
{
"request_id": "kotoba-stt_019dxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"status": "COMPLETED",
"model_id": "kotoba-stt",
"error": null,
"output": {
"media_url": [
"https://pub-582b7213209642b9b995c96c95a30381.r2.dev/v1/{request_id}/output.json"
],
"media_type": "application/json",
"text": "The transcript of the audio.",
"words": [
{
"text": "The",
"start": null,
"end": null,
"type": "word",
"speaker_id": null
}
],
"language_code": "en",
"language_probability": 0.98,
"audio_duration_secs": 17.03
},
"created_at": "2026-10-09T10:04:54.387Z",
"completed_at": "2026-10-09 10:06:21"
}Response Fields
| Field | Type | Description |
|---|---|---|
| request_id | string | Unique request identifier. |
| status | string | QUEUED, PROCESSING, COMPLETED or ERROR. |
| model_id | string | The model that handled the request — kotoba-stt for this endpoint. |
| output.text | string | The transcript. It is empty for audio without speech. |
| output.words | array of objects | The transcript word by word: text, type (word, spacing or audio_event), and start / end in seconds with with_timestamps, speaker_id with diarization. |
| output.language_code | string | The language used: the language you sent. |
| output.language_probability | number | 1, because the language comes from your request. |
| output.audio_duration_secs | number | The length of the audio in seconds: what the request is billed for. |
| output.truncated | boolean | Present and true only when a text longer than 32 KB was shortened in this response; the file at output.media_url[0] holds it in full. |
| output.media_url | array of strings | URL of a JSON file holding the same fields in full. |
| output.media_type | string | application/json. |
| created_at | string | Request creation timestamp. |
| completed_at | string | Completion timestamp. |
| error | string | Error message when status is ERROR. |
| polling_url | string | Status URL for this request (submit response only). |
Status Values & Flow
QUEUED → PROCESSING → COMPLETED (success) or ERROR (failure).
Typical workflow
- Send the request to
POST https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text. - Save the
request_idfrom the202response. - Poll
GET /v2/requests/status/{request_id}every 10 seconds or so, or use a Webhook instead. - When
statusisCOMPLETED, read the transcript inoutput.text(the same JSON is stored as a file atoutput.media_url[0]).
How Billing Is Measured
Billing is measured per second of audio: the length of the file you send, rounded up to the next whole second, 2 minutes at most. A hold for the longest file the API accepts is placed when you submit; when the transcript is ready, the charge is set from the audio's length, shown in output.audio_duration_secs, and the rest of the hold is released. Timestamps, speakers and keywords do not change the amount. A failed request is not charged. The current rate is shown in the pricing panel on this page.
Kotoba Speech-to-Text API Pricing
⚡ Performance
Live usage measured on Pixazo's gateway, split by model version. Generation time is how long a generation takes end-to-end (lower is better). Success rate is the percent of generations that complete (higher is better).
〰 Uptime
Percent of generations that succeeded over the selected period, per model version.