이 API는 완성된 오디오 파일을 대기열 작업으로 전사합니다. 파일을 제출한 뒤 반환된 작업 ID를 보관하고 처리가 끝날 때까지 작업을 조회하세요. 모든 요청은 HTTPS로 전송하고 계정의 인증 정보를 사용하세요. 예제에 나온 HTTP Basic 인증 정보 또는 API 토큰을 사용할 수 있으며, 자세한 내용은 인증을 참조하세요. 인증 정보는 서버에 보관하세요.
엔드포인트
두 API 호스트인 https://api.multi.tel 및 호환 호스트 https://api.multitel.net은 계정 범위의 작업, 멱등성 키, 제한, 과금을 공유합니다. 업로드 인코딩과 응답 봉투 형식이 다르므로 해당 형식에 맞는 파서와 함께 한 호스트를 일관되게 사용하세요.
| 작업 | 메서드 및 경로 |
|---|---|
| 서비스 정보 | GET /v3/speech_to_text |
| 작업 제출 | POST /v3/speech_to_text |
| 작업을 만들지 않고 견적 확인 | POST /v3/speech_to_text/estimate |
| 작업 조회 | GET /v3/speech_to_text/JOB_ID |
| 결제 대기 작업 정산 | POST /v3/speech_to_text/JOB_ID/settle |
| 사용량 | GET /v3/speech_to_text/usage |
호스트가 api.multi.tel인 경우 모든 경로에 접두사 /v1/speech-to-text를 /v3/speech_to_text 대신 사용할 수도 있습니다. 예: POST /v1/speech-to-text/estimate. 호스트가 api.multitel.net인 경우 /v3/speech_to_text 경로를 사용하세요.
서비스 정보 응답에는 mode (batch), realtime (false), paidEnabled (현재 새 유료 제출을 허용하는지 여부), pricePerMinuteUsd (0.005), billingUnit (audio_second), maxAudioSeconds (7200), maxUploadBytes (26214400), 그리고 짧은 description이 포함됩니다. 조회는 무료이며 유료 제출이 비활성화되어도 가능합니다. 서비스 전체를 이용할 수 없을 때만 503 transcription_unavailable을 반환합니다.
오디오 파일 준비
최대 25 MiB(26,214,400바이트), 최대 2시간(7,200초)의 완성된 오디오 파일을 사용하세요. 제출 시 오디오 스트림을 포함하는 MP3, WAV, Ogg, FLAC, MOV 또는 Matroska 미디어로 인식되어야 하며, 메타데이터의 길이가 영보다 크고 7,200초 이하여야 합니다. 인식은 되지만 이 검사를 통과하지 못하는 파일은 422 unsupported_audio 오류로 거부됩니다. 현재 이러한 형식으로 읽을 수 없는 파일은 대신 서버 오류(500)로 거부될 수 있습니다. 해당 파일을 수정 없이 다시 제출하지 마세요. 파일 확장자만으로는 호환성을 판단할 수 없습니다.
이 검사를 통과해도 오디오를 디코딩할 수 있다는 보장은 없습니다. 오디오는 하나 또는 두 개의 채널로 처리됩니다. 오디오 채널이 두 개를 초과하는 파일, 디코딩 후 오디오가 2시간을 초과하는 파일, 그 밖에 처리 중 디코딩에 실패하는 파일은 최종적으로 failed 작업이 되며, 일반적으로 decode_failed이 설정되고 요금은 부과되지 않습니다. 제출 전에 다중 채널 오디오를 모노 또는 스테레오로 변환하세요.
선택 사항인 언어 힌트는 말하는 언어를 나타내는 소문자 두 글자 또는 세 글자의 코드입니다. 예: en. 힌트를 주지 않으려면 필드를 생략하세요. api.multi.tel은 빈 문자열을 거부합니다. 힌트는 처리 방향을 안내하지만 지원 언어 목록과 대조하지는 않으므로 실제로 말하는 언어의 유효한 코드를 사용하세요.
전사 작업 제출
JSON을 Content-Type: application/json 헤더와 함께 POST https://api.multi.tel/v3/speech_to_text로 보내세요. 요청 본문은 최대 35 MiB이며, 최대 크기 파일을 base64로 인코딩한 데이터가 들어갈 수 있습니다. 이보다 큰 본문은 413으로 거부됩니다.
| 필드 | 의미 |
|---|---|
audioBase64 | 필수. 표준 base64로 인코딩한 전체 파일(A–Z, a–z, 0–9, +, /)이며, 필요한 경우 = 패딩을 붙입니다. data-URL 접두사, 줄바꿈, 공백을 추가하지 말고 URL 안전 문자 집합도 사용하지 마세요. 값의 디코딩 결과는 1바이트 이상 25 MiB 이하여야 하며, 다시 인코딩하면 원문과 정확히 같아야 합니다. |
language | 위에서 설명한 선택적 언어 힌트입니다. |
다른 모든 JSON 속성은 idempotency_key를 포함하여 400 invalid_transcription_request로 거부됩니다. 키는 헤더로 보내세요.
멱등성 키
각 제출에는 Idempotency-Key 헤더가 필요하며 길이는 1~190자여야 합니다. ASCII 영문자, 숫자, -, _, . 및 :을 사용하고 앞뒤 공백은 넣지 마세요. 호환 호스트는 앞뒤 공백을 제거하고 키를 바이트로 측정하므로 다른 문자는 호스트마다 다르게 셀 수 있습니다. 키가 없거나 191자 이상이면 400으로 거부됩니다.
키는 양쪽 호스트와 계정의 모든 인증 정보에 걸쳐 해당 계정의 음성 텍스트 변환에 적용됩니다. 같은 키로 같은 파일과 언어를 다시 보내면 기존 작업과 HTTP 200, duplicate: true가 반환되며, 작업 상태나 작업 생성 이후 처리 방식의 업데이트 여부와 관계없이 추가 요금이 없습니다. 같은 키를 다른 파일 또는 언어에 재사용하면 409 idempotency_conflict를 반환합니다. 새 키를 쓰면 같은 파일이어도 새 작업이 생성되며, 처리가 성공적으로 완료되면 별도의 요금이 부과됩니다.
API_USER="your-api-username"
API_PASSWORD="your-api-password"
node -e 'process.stdout.write(JSON.stringify({audioBase64:require("node:fs").readFileSync("completed-call.mp3").toString("base64"),language:"en"}))' > completed-call.json
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: speech-call-001" \
--data-binary @completed-call.json \
-o speech-job.json \
https://api.multi.tel/v3/speech_to_text
node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).data.id'새 작업은 HTTP 202와 아래 필드를 반환하며, 재전송은 HTTP 200과 전사 결과 읽기에 설명된 전체 작업 객체를 반환합니다. 작업 ID는 UUID이며 data.id에서 읽으세요. 새 작업의 응답은 다음과 같습니다(식별자와 값은 예시입니다).
{
"status": "success",
"data": {
"id": "3f6c1b2e-8a4d-4e7f-9c21-5b0d7e4a9f13",
"status": "queued",
"mode": "batch",
"realtime": false,
"source": "api",
"durationSeconds": 90.5,
"billedSeconds": 91,
"costUsd": "0.007583334",
"pricePerMinuteUsd": "0.005"
}
}작업이 대기 중이거나 실행 중이면 durationSeconds, billedSeconds 및 costUsd는 파일 메타데이터에서 구한 추정치입니다. 최종 요금은 디코딩된 길이를 기준으로 합니다.
제출 시 선불 잔액으로 해당 작업과 다른 미정산 작업의 비용을 충당할 수 없으면 402 insufficient_balance, 계정 또는 서비스의 미완료 작업이 너무 많으면 429 transcription_queue_full, 파일 검증 처리 용량이 가득 차면 429 audio_validation_busy, 유료 전사가 비활성화되어 있으면 503 paid_transcription_not_enabled도 반환할 수 있습니다. 429 및 503 응답은 나중에 같은 키로 재시도하세요.
작업을 만들지 않고 견적 확인
같은 JSON 본문을 POST https://api.multi.tel/v3/speech_to_text/estimate로 보내세요. 멱등성 키는 필요하지 않습니다. 견적은 파일을 검증하고 길이를 측정하지만 전사, 작업 생성, 자금 예약, 잔액 확인, 과금은 하지 않습니다. language 힌트는 허용하지만 견적에는 영향을 주지 않습니다.
견적이 성공하면 HTTP 200을 반환하며 estimate: true, charged: false, mode, realtime, durationSeconds, billedSeconds, pricePerMinuteUsd 및 costUsd가 data 아래에 포함됩니다. 견적에는 파일 메타데이터의 길이를 사용하지만 완료된 작업은 디코딩된 길이로 과금하므로 둘은 다를 수 있습니다. 견적도 제출과 같은 파일 검사를 수행합니다. 유료 전사가 활성화되어 있을 때만 이용할 수 있습니다(그렇지 않으면 503 paid_transcription_not_enabled). 파일 검증 처리 용량이 가득 차면 429 audio_validation_busy를 반환할 수 있습니다. 잠시 후 재시도하세요.
전사 결과 읽기
다음 경로를 폴링하세요: GET /v3/speech_to_text/JOB_ID. 방법은 작업 흐름 가이드를 참조하세요. 작업 객체에는 다음 필드가 포함됩니다.
| 필드 | 의미 |
|---|---|
id | 작업 UUID입니다. |
status | queued, running, completed, failed 또는 awaiting_payment. |
progress | 실행 중에는 가능한 경우 0~99의 백분율, 완료 시 100, 그 밖의 경우 null입니다. |
durationSeconds, billedSeconds | 오디오 길이와 과금 대상 정수 초입니다. 대기 중이거나 실행 중이면 메타데이터 추정치이며, 완료되었거나 결제 대기 중이면 디코딩된 길이를 사용합니다. |
costUsd, costIsEstimate | 소수점 아래 아홉 자리의 십진 문자열로 표시한 미국 달러 비용입니다. costIsEstimate는 작업이 대기 중이거나 실행 중일 때 true입니다. 실패한 작업은 costUsd에 추정치가 남아 있어도 과금되지 않습니다. |
pricePerMinuteUsd | 0.005는 API 작업에 적용되며, 0.000은 무료 Hosted PBX 녹음 작업에 적용됩니다. |
failureCode | 실패한 작업의 경우: decode_failed (오디오를 디코딩하지 못함. 예: 채널이 두 개를 초과하거나 디코딩 후 2시간을 초과), inference_timeout (처리 시간이 너무 오래 걸림), service_error 또는 worker_lease_lost (처리가 중단됨). 코드 unsupported_audio 및 quality_check_failed도 정의되어 있습니다. 결제 대기 작업은 insufficient_balance를 표시하며, 정산 후에도 남아 있을 수 있습니다. |
source, modelVersion, createdAt | source는 API 제출이면 api, 계정의 Hosted PBX 녹음 작업이면 hpbx입니다. modelVersion은 내부 구조를 해석하지 않고 다루는 처리 버전 문자열입니다. createdAt은 제출 시각입니다. |
duplicate | true는 기존 작업을 반환하는 응답에 설정됩니다. |
result | 다음 조건에서만 존재합니다: status가 completed. |
| 결과 필드 | 의미 |
|---|---|
text | 전체 전사문입니다. 모든 구간의 텍스트를 구간 순서대로 줄바꿈으로 연결합니다. |
segments | 시작 시간순으로 정렬된 구간 배열입니다. 각 구간은 최대 약 29초의 오디오 부분을 다룹니다. 해당 start와 end (오디오 시작부터의 초)는 개별 단어나 문장이 아닌 해당 부분을 가리키며, 연속된 부분은 최대 1초 겹칠 수 있습니다. 각 구간에는 text 및 language (언어 코드이며 비어 있을 수 있음)가 있고, 두 채널 결과에는 channel도 있습니다. |
channelCount | 1 또는 2입니다. 현재 결과에는 포함되지만 이전 결과에서는 생략될 수 있습니다. |
audioDurationMs | 밀리초 단위의 디코딩된 길이입니다. 과금 시 정수 초로 올림합니다. |
qualityFlags | 비어 있거나, review_recommended와 함께 repetition_detected (구간 내에서 특정 구절이 비정상적으로 자주 반복됨), no_speech (전사된 음성이 없음), 또는 둘 다 포함됩니다. |
pipelineVersion | 포함될 수 있습니다. 내부 구조를 해석하지 않고 다루는 처리 식별자입니다. |
전사문과 타임스탬프, 언어 라벨, 채널 라벨은 자동 생성되며 정확성이 보장되지 않습니다. 품질 플래그가 있으면 결과를 검토하고, 중요한 이름, 숫자, 약속 내용을 원본 오디오와 비교하세요. 긴 무음과 매우 조용한 부분은 건너뛰며 구간이 생성되지 않습니다. 결과는 개별 화자를 식별하지 않습니다. 결과의 channelCount가 2이면 각 구간의 channel은 A (첫 번째, 즉 왼쪽 채널) 또는 B (두 번째, 즉 오른쪽 채널)입니다. 화자를 구분할 수 있는 것은 각 화자가 별도 채널에 녹음된 경우뿐입니다. 두 채널 오디오는 경과 길이로 한 번 과금하며 채널별로 과금하지 않습니다. 모노 결과에는 채널 라벨이 없습니다.
api.multitel.net 사용
호환 엔드포인트 POST https://api.multitel.net/v3/speech_to_text는 multipart/form-data를 받습니다. 이 형식에서는 audio 파일 파트와 선택적 language 필드를 사용하며 JSON audioBase64는 사용하지 않습니다. 빈 language 값은 힌트 없음으로 처리합니다. 같은 Idempotency-Key 헤더를 보내세요. 헤더가 없으면 이 호스트는 idempotency_key 폼 필드도 받습니다. 필드 이름이 source, free, billing_source, realtime 또는 stream이면 400 unsupported_transcription_option으로 거부되며, 그 밖의 폼 필드는 무시합니다. 이 호스트는 다음 오류도 반환합니다.
- 400
idempotency_key_required: 키가 없거나 너무 긴 경우. - 400
audio_upload_required: 업로드가 없거나 완전히 수신되지 않은 경우. - 400
invalid_language: 언어가 유효하지 않은 경우. - 413
invalid_audio_size: 파일이 비어 있거나 너무 큰 경우. - 400
invalid_job: 작업 ID 형식이 잘못된 경우.
이 호스트의 음성 텍스트 변환 서비스 응답은 봉투 형식 {"status":{"code":HTTP_STATUS},"response":{...}}을 사용합니다. status는 문자열이 아닌 객체입니다. 성공 시 response에는 기본 호스트의 data와 같은 객체가 들어 있으므로 작업 ID는 response.id입니다. 오류 시 response.code에 오류 코드가 들어 있으며 메시지나 요청 ID는 포함되지 않습니다. 인증 실패(401)는 호스트 공통 로그인 검사에서 반환되며 본문이 다를 수 있으므로 파싱 전에 HTTP 상태를 확인하세요. 호스트 간에 업로드 인코딩이나 응답 파서를 혼용하지 마세요.
이 호스트에서 견적을 받으려면 같은 multipart 필드를 /v3/speech_to_text/estimate에 POST하세요. 멱등성 키는 필요하지 않으며 견적은 response 아래에 있습니다.
API_USER="your-api-username"
API_PASSWORD="your-api-password"
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
-H "Idempotency-Key: speech-call-001" \
-F "audio=@completed-call.mp3" -F "language=en" \
-o speech-job.json \
https://api.multitel.net/v3/speech_to_text
node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).response.id'