Kotoba Speech-to-Text API: Pricing, Documentation

by Kotoba Technologies

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.

Get API Key
Kotoba Speech-to-Text API

Models Version

WELCOME BONUS

Get 10% Cashback on Your First Payment (up to $500)

Add funds and get 10% cashback on your first payment (up to $500).

Claim Your Cashback →

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-text

Authentication

All requests require an API key passed via header.

HeaderTypeRequiredDescription
Ocp-Apim-Subscription-KeystringYesYour 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.

HeaderRequiredDescription
X-Webhook-URLTo enableHTTPS URL to receive the Webhook callback.
X-Webhook-ModeNoterminal (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 200 within a few seconds; the Webhook endpoint must be HTTPS.

Request Parameters

ParameterRequiredTypeDefaultAllowed values / rangeDescription
audio_urlYesstring—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 M4AThe speech to transcribe. A file that states a longer length is refused at submit.
languageYesstring—ja, en, ko, zh, es, zh-hk, zh-twThe language spoken in the audio. The model does not detect it.
with_timestampsNobooleanfalsetrue, falseReturn a start and end time for each word in output.words.
diarizationNobooleanfalsetrue, falseAttribute each word to a speaker (speaker_id). Word times stay empty unless with_timestamps is also true.
keywordsNoarray—Up to 1000 terms of at most 64 characters eachNames or product words whose spelling the transcript should prefer.
kanaNobooleanfalsetrue, falseWrite personal and place names in katakana (Japanese).

Good to know

  • Each request returns one transcript. batch_size, num_images, number_of_images, n and count are 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_second and music_length_ms are rejected.
  • Send every field at the top level of the JSON body; parameters, content and text are rejected.
  • Send one audio file as audio_url: a publicly reachable https URL (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 with status: "ERROR", and nothing is charged.
  • language is required: ja, en, ko, zh, es, zh-hk or zh-tw. The model does not detect the language, so send the one spoken in the audio.
  • keywords takes at most 1000 terms of at most 64 characters each; a longer term fails the request with status: "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_urls is rejected (send one file per request, as audio_url).
  • prompt is rejected (use keywords to suggest the spelling of names and terms).
  • language_code is rejected (send the language as language).
  • Use the JSON types shown: audio_url and language are strings, with_timestamps, diarization and kana are true or false (not "true"), and keywords is a list of strings.
  • Omit a field instead of sending null.
  • Results are always returned as a URL in output.media_url; sync_mode is accepted only as false.
  • Webhooks are set with the X-Webhook-URL / X-Webhook-Mode headers; webhook_url, webhook_mode and callback_url in the JSON body are rejected.
  • stream is not supported: the result is delivered when the job completes.
  • Options this API does not offer are rejected: input and model.

Timestamps, Speakers and Keywords

  • With with_timestamps true, each entry of output.words carries start and end in seconds.
  • With diarization true, each word carries a speaker_id; send with_timestamps too if you need the times.
  • output.words holds words, the spaces between them (type spacing) and sound events such as laughter (type audio_event).
  • keywords only 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

HeaderRequiredDescription
Content-TypeYesapplication/json
Ocp-Apim-Subscription-KeyYesYour API subscription key.
X-Webhook-URLNoEnable Webhook callbacks (see Webhook section).
X-Webhook-ModeNoterminal (default) or sync (see Webhook section).

Response Handling

Status CodeMeaning
202Accepted — request queued; returns request_id and polling_url.
400Invalid 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.
401Unauthorized — missing or invalid subscription key.
402Insufficient balance for the hold this request needs.
429Too many requests.
500Internal 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.

ConditionHow it surfaces
Missing or invalid subscription keysynchronous 401
Balance too low for the holdsynchronous 402
Missing or empty audio_url, audio_url not a stringsynchronous 400
Missing or empty language, language not a stringsynchronous 400
keywords not a list, or more than 1000 itemssynchronous 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 decodestatus: "ERROR"
Audio longer than 2 minutes whose file did not state its lengthstatus: "ERROR"
A keywords term longer than 64 charactersstatus: "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_KEY

cURL 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

FieldTypeDescription
request_idstringUnique request identifier.
statusstringQUEUED, PROCESSING, COMPLETED or ERROR.
model_idstringThe model that handled the request — kotoba-stt for this endpoint.
output.textstringThe transcript. It is empty for audio without speech.
output.wordsarray of objectsThe 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_codestringThe language used: the language you sent.
output.language_probabilitynumber1, because the language comes from your request.
output.audio_duration_secsnumberThe length of the audio in seconds: what the request is billed for.
output.truncatedbooleanPresent 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_urlarray of stringsURL of a JSON file holding the same fields in full.
output.media_typestringapplication/json.
created_atstringRequest creation timestamp.
completed_atstringCompletion timestamp.
errorstringError message when status is ERROR.
polling_urlstringStatus URL for this request (submit response only).

Status Values & Flow

QUEUED → PROCESSING → COMPLETED (success) or ERROR (failure).

Typical workflow

  1. Send the request to POST https://gateway.pixazo.ai/kotoba-stt/v1/speech-to-text.
  2. Save the request_id from the 202 response.
  3. Poll GET /v2/requests/status/{request_id} every 10 seconds or so, or use a Webhook instead.
  4. When status is COMPLETED, read the transcript in output.text (the same JSON is stored as a file at output.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

Your request will cost $0.0083 per second of audio.

⚡ 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).

Show data for the last
Generations
300last 30d
~10 per day
Success rate
66.7%
of completed generations
Generation time
17.3savg
p95 11.1s
Requests
Oct 16max 300Nov 14
Kotoba Speech-to-TextAvg 10/day
Generation Time
Oct 16max 17.3sNov 14
Kotoba Speech-to-TextAvg 17.3s
Error Rate
Oct 16max 33.3%Nov 14
Kotoba Speech-to-TextAvg 33.3%

〰 Uptime

Percent of generations that succeeded over the selected period, per model version.

Avg. Success Rate (30d)
66.67%
across all generations of this model family
Uptime
Oct 16max 100%Nov 14
SuccessfulAvg 66.67%