Replace SERVICE below with speech_to_text or translate, and JOB_ID with the returned UUID. All operations require credentials for your account, as described in Authentication, and are scoped to the owning account. A job can be read from either API host, but each host uses its own envelope, so use one host consistently.
| Host | Success | Error |
|---|---|---|
api.multi.tel | {"status":"success","data":{...}} | {"status":"error","code":"...","message":"...","requestId":"..."} |
api.multitel.net | {"status":{"code":200},"response":{...}} | {"status":{"code":409},"response":{"code":"idempotency_conflict"}} |
On api.multitel.net, authentication failures (401) are returned before this envelope is applied and can have a different body, so check the HTTP status before parsing.
Authentication
Every request must carry credentials for your account. Jobs, idempotency keys, limits, usage and charges belong to the account that owns the credentials. They are shared by all of that account's credentials on both hosts, whichever credential sends a request.
- HTTP Basic (
Authorization: Basic, orcurl --user). Accepted credentials are an API account of the password type, a subaccount, or your account login. We recommend a dedicated API account. The username cannot contain a colon, and neither the username nor the password can be empty. - Bearer token (
Authorization: Bearer YOUR_TOKEN). Accepted for an API account of the token type. Token API accounts must have an IP restriction, and requests must come from a permitted address. Both API hosts accept the account's configured IPv4 addresses and CIDR ranges. A token cannot be sent as a Basic password. Confirm that your token works on the host you use.
API_TOKEN="your-api-token"
curl --fail-with-body --silent --show-error \
-H "Authorization: Bearer $API_TOKEN" \
https://api.multi.tel/v3/speech_to_textIf an API account is restricted by IP address, send requests from a permitted address. Missing or invalid credentials return 401. On api.multitel.net, credentials that are valid but cannot use these services, such as a token account's credentials sent as Basic, return 403 unsupported_transcription_principal or unsupported_translation_principal. Repeated failed authentication from one address on api.multitel.net can cause that address to be blocked, so fix credentials before retrying.
Poll for completion
Request GET /v3/SERVICE/JOB_ID. We recommend polling no more often than once every 3 seconds. The outer envelope describes the request; inspect the inner job's status to determine whether processing has finished.
| Status | Meaning |
|---|---|
queued | Accepted and waiting. Jobs for one account are processed one at a time, in turn with other accounts. |
running | Processing. progress can be null; a null value alone does not mean the job has stalled. |
completed | The result is available. Preserve it and compare important details with the source. |
failed | Inspect failureCode. Failed work is not charged. Correct the cause and submit with a new key; resending the same key returns the same failed job. |
awaiting_payment | Processing finished, but a prepaid balance could not cover the charge. The result is saved and withheld until the job is settled. |
API_USER="your-api-username"
API_PASSWORD="your-api-password"
SERVICE="speech_to_text"
HOST="https://api.multi.tel"
JOB_ID=$(node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).data.id')
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
"$HOST/v3/$SERVICE/$JOB_ID"On api.multitel.net, set HOST to https://api.multitel.net and read .response.id instead of .data.id.
Retry uncertain requests safely
If a submission times out or returns 429 or a 5xx status, resend the same input with the same idempotency key. A response from either host can be lost or replaced with an error after the work was accepted; resending with the same key returns the job if it exists. A key reused with different input returns 409 idempotency_conflict. Some errors repeat on every attempt, such as 503 while a paid service is disabled or 500 for an audio file that cannot be read, so stop after a few attempts.
Changing a key has different effects for each service.
- For speech-to-text, a new key creates a new job with a separate charge if processing completes successfully. The original key keeps returning the original job, even after processing is updated.
- For translation, a new key with identical content returns a matching queued, running, completed or awaiting-payment job at no new charge. It creates new work if the earlier job failed or the processing version has changed. A translation retry with the original key returns 409 after a processing-version change, so retain the original job ID and read the job directly.
Release a result after adding funds
For a job in awaiting_payment, add funds so that your balance is at least the job's costUsd rounded up to the next $0.00001, then send POST /v3/SERVICE/JOB_ID/settle. Debits are made in whole steps of $0.00001 and include any remainder carried from earlier jobs of the same service, so the amount debited can exceed costUsd by less than $0.00001. On api.multi.tel, send JSON {} or an empty body; any property in the body is rejected with 400. api.multitel.net ignores the body. Settlement releases the saved result without running transcription or translation again. The response contains the job; check that its status is completed. If the balance is still insufficient, the job remains awaiting_payment and the response is still HTTP 200.
For speech-to-text, settling an already completed job returns it with duplicate: true, and settling a queued, running or failed job returns 409 transcription_not_awaiting_payment. For translation, settling a job in any other status returns the job unchanged. Settlement is available only while paid processing is enabled (otherwise 503). Jobs awaiting payment count as reserved cost, so for prepaid accounts they can block new paid submissions with 402 until they are settled.
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
-X POST -H "Content-Type: application/json" --data '{}' \
"$HOST/v3/$SERVICE/$JOB_ID/settle"Check usage
Use GET /v3/SERVICE/usage. Optional from and to parameters are UTC dates in YYYY-MM-DD format, and both boundary dates are included. If omitted, from defaults to 30 days before today and to defaults to today (UTC). to must not be earlier than from, and the dates can be at most 366 days apart (up to 367 dates). Invalid calendar dates or a reversed or longer range return 400, and so do other query parameters on api.multi.tel.
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
"$HOST/v3/$SERVICE/usage?from=2026-10-01&to=2026-10-31"The response contains mode, currency (USD), from, to and days, a list ordered newest first.
- Speech-to-text entries are grouped by date and source. They contain
date,source(api, orhpbxfor Hosted PBX recordings),files,audioSeconds,billedSeconds,accruedUsdanddebitedUsd. - Translation entries are grouped by date, source and engine. They contain
date,source,engine,jobs,sourceCharacters,accruedUsdanddebitedUsd.
accruedUsd is the exact cost with nine decimal places, and debitedUsd is the amount debited, with five. Usage is recorded on the UTC date each job's charge settled, so queued, running, failed and awaiting-payment jobs do not appear.
Limits
Each account can have at most 50 outstanding speech-to-text and translation jobs combined: queued, running or awaiting payment, including Hosted PBX recording work. When that limit or overall service capacity is reached, submissions return 429 transcription_queue_full or translation_queue_full. api.multi.tel also limits each client IP address to 300 requests per minute across all requests to that host. That limit returns 429 with rate-limit headers and a plain-text body rather than the JSON error envelope.
Handle request errors
On the primary host, failures return an HTTP error status and JSON with status: "error", code, message and requestId. Each response also carries an X-Request-ID header. You can supply your own value; values longer than 128 characters are truncated. The compatibility host returns only the error code in response.code. Log the request ID, where available, and the error code, and keep audio, text and credentials out of logs.
Common statuses:
| Status | Meaning |
|---|---|
| 400 | Invalid input. |
| 401 | Missing or invalid credentials. |
| 402 | Insufficient prepaid balance. |
| 403 | On the compatibility host, credentials that cannot use these services. |
| 404 | An unknown job or route. |
| 405 | An unsupported method, or an unknown path within a service. |
| 409 | Conflicting input, a same-language translation, or settling a speech job that is not awaiting payment. |
| 413 | An oversized body or file. |
| 422 | Unsupported audio, or an unavailable standard language pair. |
| 429 | Queue, validation or request-rate limits. |
| 500 | An unexpected server error, including an audio file that cannot be read. |
| 503 | A disabled or temporarily unavailable service, or credentials that cannot be checked at the moment. |
Follow the returned error code rather than assuming every validation failure has one status.
For 429 or 503, wait and retry with backoff and the same submission key; honor Retry-After when present. For invalid input or credentials, fix the cause first. Do not repeatedly submit new keys while earlier jobs are still queued.