Audio + transcripts.
One ranking.
Bring candidate transcripts, or let Bessel generate them from the models you choose. Both modes compare transcripts against your audio.
Two ways to use Bessel.
| Mode | You provide | Bessel returns |
|---|---|---|
| Submit transcripts | Audio + 2–4 candidate transcripts from any source | Candidate rankings, relative scores and a supported recommendation or explicit uncertainty |
| Choose models | Audio + 2–4 supported ASR models | Generated transcripts, their rankings, scores and model availability |
Use /v1/rank when your pipeline already has transcripts, including private models or multiple outputs from one model. Use /v2/comparisons when you want Bessel to obtain the transcripts first. The Playground keeps the convenient upload-and-select-models workflow.
Rank your own transcripts.
POST /v1/rank accepts a multipart request containing one audio clip and 2–4 candidate transcripts. Candidates may come from different providers, your own model or multiple outputs of one model. No default model is required.
This is a synchronous endpoint. It compares the supplied text against the audio and returns JSON; it does not run candidate ASR services or rewrite your transcripts.
Try the public API
Replace clip.wav and the example text with your own matching clip and transcripts. The Origin header below selects the website; it is not an API key. The free audio allowance applies.
curl 'https://asrouter-api.mangoground-d47f75d9.northcentralus.azurecontainerapps.io/v1/rank' \
-H 'Origin: https://www.besselaudio.com' \
-F 'audio=@clip.wav' \
-F 'candidates=[{"id":"a","text":"The meeting is on Friday."},{"id":"b","text":"The meeting is on Thursday."}]'Allow up to 200 seconds for a response. A busy or unavailable service returns an error, not a fabricated ranking.
Request fields.
- audio · required file
- One MP3, WAV or FLAC recording, 0.1–15 seconds long and up to 3 MiB. Every candidate must cover this exact recording.
- candidates · required JSON array
- 2–4 objects with
idandtext. IDs must be unique, 1–96 characters, using letters, digits, underscores, dots, slashes or hyphens. Text must be nonempty and at most 2,000 characters per candidate. - source · optional candidate metadata
- A label of 1–120 characters, such as a model or decoding version. Multiple candidates may have the same source. Source labels do not influence the comparison.
- language · optional form field
- Omit this field or use
autofor automatic processing. You can also supply a short code such asen,es,jaorar, or a full language/script code such ashin_Deva. See supported languages.
Candidate IDs identify outputs, not globally ranked models. Names and source labels are not evidence of transcription quality.
Supported languages.
Bessel can rank candidate transcripts in 1,650 languages, with 1,672 language, writing-system and dialect configurations. Language is optional: omit it or use auto. Automatic processing can compare audio and text even when the language cannot be confidently identified from a short transcript.
| Input mode | Language coverage |
|---|---|
| Audio + candidate transcripts | Use any transcription source and a supported ranking language. Coverage is independent of the 29 ASR models in the Playground. |
| Audio + selected ASR models | Each selected ASR must support the recording’s language. Bessel ranks the transcripts they return. Selecting a model does not extend that model’s language coverage. |
Common hints include en, zh, fr, es, de, it, pt, ja, ko, ar, hi, ru, bn, ta, th, vi and sw. For a specific writing system or dialect, use the exact code from the catalog.
Get the full language catalog
GET /v1/languages returns language_count, profile_count and a languages array. Each entry contains code, name, script and accepted aliases. This endpoint does not require sign-in or consume audio allowance.
curl 'https://asrouter-api.mangoground-d47f75d9.northcentralus.azurecontainerapps.io/v1/languages'Use this catalog to populate language options in your application. A supplied language code outside the catalog returns HTTP 422. Scores remain relative comparisons; the same uncertainty rules apply in every language.
Read the response.
Illustrative response; these numbers are not a measured result for the example above.
{
"status": "ranked",
"best_candidate_id": "b",
"ranking": [
{"candidate_id": "b", "rank": 1, "ranking_score": 0.82},
{"candidate_id": "a", "rank": 2, "ranking_score": 0.18}
],
"probabilities_calibrated": false
}- status · enum
ranked: there is sufficient comparative support for the unique first candidate.equivalent: all candidates are equivalent under the comparison’s text normalization.insufficient_evidence: relative scores are available, but there is no supported recommendation.- best_candidate_id · string or null
- An input ID only when status is
ranked; otherwisenull. Your application decides whether to use it, retain its existing result or request review. - ranking · array
- Every input candidate appears exactly once, sorted by descending
ranking_score. Equal scores share a rank, such as 1, 1, 3. Input order only breaks the display order within an equal-score group. - ranking_score · number from 0 to 1
- A relative comparison score for this candidate set. It is not an accuracy percentage, measured WER, confidence or calibrated probability of being best. Changing the candidate set can change the score.
- probabilities_calibrated · false
- The API does not return calibrated probabilities. No confidence threshold is implied by a score.
A ranking can accompany insufficient_evidence. Do not treat the first row alone as a recommendation. Even a recommended candidate can be inaccurate; this endpoint does not certify absolute quality or detect every case where all candidates are poor.
Limits and errors.
- Ranking: 2–4 candidates; 0.1–15 seconds; 3 MiB per audio file; mono or stereo, 8–48 kHz.
- Ranking supports 1,650 languages and 1,672 language/script configurations. See language coverage.
- Anonymous access: 60 source-audio seconds per UTC day. Verified accounts: 300 seconds per UTC calendar month, shared with the automatic demo.
- Successful comparisons consume the clip duration once, regardless of candidate count. Equivalent or inconclusive comparisons are completed work. Failed requests release their reservation.
- The synchronous ranking endpoint does not store a resumable result. Save the JSON response if you need it later. Retrying a completed request is a new comparison.
| HTTP status | Meaning and next step |
|---|---|
| 401 | Missing or expired account session; sign in again. |
| 403 | Origin is not allowed. Use the website or an authenticated server request. |
| 409 | A comparison is already running for this account or visitor. Wait for it to finish. |
| 413 | Audio or request exceeds the size limit; use a smaller clip. |
| 422 | Invalid audio, candidates or language. Correct the input; do not retry it unchanged. |
| 429 | Service busy, request limit reached or allowance exhausted. Read the error detail. Respect Retry-After when present and back off. |
| 502 / 503 / 504 | Invalid upstream result, unavailable service or timeout. Retain your current transcript and retry later. |
Errors use {"detail":"error_code"}. Stopping the browser request does not guarantee that processing stops; submitted work may finish and consume allowance.
Choose models and generate candidates.
Upload audio and select 2–4 of the 29 supported ASR models. Bessel obtains their transcripts, compares them against the recording and returns the results together. This is the existing Playground workflow; no pasted text is needed.
POST /v2/comparisons accepts MP3, WAV or FLAC recordings up to 5 minutes and 64 MiB, using asynchronous jobs. Anonymous visitors can submit up to 60 seconds per recording within their daily allowance; verified accounts can submit up to 5 minutes within their monthly allowance.
Create a comparison
curl 'https://asrouter-api.mangoground-d47f75d9.northcentralus.azurecontainerapps.io/v2/comparisons' \
-H 'Origin: https://www.besselaudio.com' \
-H 'Idempotency-Key: example-request-0001' \
-F 'audio=@clip.wav' \
-F 'models=["azure/speech-fast","azure/llm-speech"]' \
-F 'default_model=azure/speech-fast'models is a JSON array of unique supported model IDs. default_model must be one of them. Retrieve the current catalog with GET /v1/models. The language is inferred automatically.
Use a new Idempotency-Key for each new comparison: 16–80 letters, digits, underscores or hyphens. Reuse the same key and input only to recover a submission whose outcome is unknown. An accepted request returns HTTP 202 with an id, job status, stage, progress, poll_after_seconds and quota.
Read progress and results
curl 'https://asrouter-api.mangoground-d47f75d9.northcentralus.azurecontainerapps.io/v2/comparisons/COMPARISON_ID' \
-H 'Origin: https://www.besselaudio.com'Replace COMPARISON_ID with the returned ID. Poll at the suggested interval and honor Retry-After. Keep the same visitor identity or account session used to submit the job; signed-in requests include the same Bearer session on submission and polling.
Job status is queued, running, complete, failed or canceled. On completion, result.candidates contains each model’s model and transcript; result.ranking contains model, rank and ranking_score, with best_probability: null. transcription_status reports model availability.
Read sections as they finish
The generated-comparison workflow splits long recordings into sections of up to 15 seconds, preferring quieter boundaries. It can transcribe a later section while comparing an earlier one. You do not need to split the file before uploading it. The synchronous /v1/rank endpoint continues to accept one matching clip and its supplied candidate transcripts.
Jobs advertise progressive_results: true. While a job is running, an optional preview contains attempt, revision, total_segments, processed_segments, compared_segments and segments. Each available section has a one-based index, start_seconds and end_seconds on the original recording timeline, candidates with model IDs and transcripts, and a possibly empty ranking. Silent sections can be omitted, leaving gaps in the timeline.
Section results are provisional and apply only to the indicated interval and candidate set. They are not a full-recording recommendation or an accuracy percentage. If a model fails later, the final comparison can contain fewer candidates and different scores. Replace the preview with result when the job finishes. The Playground displays each model's transcript as it becomes available, without waiting for every selected model. A section's optional transcription_status distinguishes pending, complete and unavailable models. Its ranking remains empty until the candidate responses for that section have been resolved. The Playground resumes available sections after a page reload.
Measure waiting and processing time
Optional request_timing_ms reports server-side upload_receive and audio preparation. Optional timing_ms reports queue time before the worker starts, processing elapsed time in the current attempt, first_transcript and first_ranking measured from worker start when available, cumulative asr_work and ranking_work, and cumulative request times per model in models. Cached work reused on retry is not counted as new provider execution. Overlapping times must not be added together to estimate total latency.
The Playground also includes client_timing_ms in a newly completed result's JSON: upload measures browser upload completion, first_result measures the first result observed by that browser, and total measures the full browser wait. Browser timings include polling and network delays; a restored result does not invent a new measurement. These are observations, not latency guarantees.
If an ASR is unavailable, other models continue. Only transcripts covering the entire recording appear in result.candidates. With at least two complete transcripts, Bessel ranks that subset and returns reason: partial_comparison when some models failed. With one complete transcript, the job completes with that transcript and an empty ranking; it consumes the recording duration once. If none complete, the job fails and releases its reservation. Failed model statuses remain available in the JSON response.
This workflow preserves default_model as selected_model and does not automatically switch your ASR. The first ranking row may differ from that default. Scores are relative and uncalibrated. Inspect reason and per-model status when ranking is unavailable; completed transcripts may still be returned.
Use POST /v2/comparisons/{id}/cancel to cancel a pending job. If a failed job has retryable: true, POST /v2/comparisons/{id}/retry resumes missing transcription parts when no model completed, or retries ranking with retained transcripts when ranking failed. Completed parts are reused. Results remain accessible to the submitting visitor or account for 24 hours.
The short-clip /v1/judge and /v1/route contracts also remain compatible. For new integrations, choose /v1/rank for supplied transcripts or /v2/comparisons for model selection. They have different response schemas: do not parse a generated comparison as a candidate-based ranking response.
Access and authentication.
The website accepts requests from its allowed origins. The curl example uses anonymous access. For a signed-in request, add Authorization: Bearer <BESSEL_ACCOUNT_SESSION>.
Server-to-server calls to /v1/rank without an Origin header require a valid Bessel account session. Account sessions expire and are not permanent API keys. Do not expose a session token in public client code or send an ASR provider’s key.
For production credentials, capacity and integration support, contact our team. Production access is arranged separately from the shared free allowance.
Contact Sonaflow ↗