문서파일 업로드

파일 업로드

95MB까지는 요청 한 번으로 보내세요. 더 큰 파일은 최대 2GB까지 청크로 나눠 올리고, 전송이 끊기면 이어서 업로드할 수 있어요.

보유한 오디오·영상 파일을 올리면 AI 음성 텍스트 변환(STT)으로 스크립트를 만들어요. 파일 업로드의 source는 auto와 stt만 허용해요. 언어와 화자 분리를 지정하는 language, diarize는 지원 링크와 변환 옵션에서 확인하세요.

파일 형식과 크기

파일 확장자는 mp3, wav, m4a, flac, ogg, opus, mp4, mov, webm, mkv 중 하나여야 해요. 다른 확장자는 422 unsupported_media를 반환해요. 지원 형식이라도 오디오 트랙이 없으면 unsupported_media로 실패해요.

항목한도
단일 요청 업로드(multipart/form-data)95MB
청크 업로드2GB(2,000,000,000바이트). 요금제에 따라 한도가 더 작을 수 있어요.
팀당 완료 전 청크 업로드최대 20개

크기 한도를 넘으면 413 media_too_large를 반환해요. 오류 응답의 max_bytes에서 허용 크기를 확인하세요.

요청 한 번으로 업로드하기

95MB 이하의 파일은 POST /v1/transcriptions에 multipart/form-data로 보내세요. 파일을 넣을 파트 이름은 file이에요. 필요하면 폼 필드에 language, diarize(true 또는 false), source(auto 또는 stt), webhook_url을 추가하세요.

curl -X POST "https://api.transcript1.com/v1/transcriptions?wait=60" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -F [email protected] \
  -F language=en \
  -F diarize=true

응답으로 받는 변환 작업 객체에서 source.platform은 upload예요. 영상 링크를 보냈을 때처럼 처리 중에는 202, 작업이 끝나면 200을 반환해요. 빈 파일을 보내면 422 invalid_request를 반환해요.

큰 파일을 청크로 나눠 올리기

큰 파일은 청크 단위로 전송하세요. 업로드가 끊겨도 아직 도착하지 않은 청크만 다시 보내면 돼요. 아래 순서대로 진행하세요.

1. 업로드 예약하기

먼저 파일 이름과 크기를 JSON으로 보내 업로드를 예약하세요. mime_type은 생략할 수 있어요. 생성 요청을 재시도해도 작업이 중복되지 않도록 Idempotency-Key 헤더를 넣으세요.

curl -X POST "https://api.transcript1.com/v1/transcriptions" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Idempotency-Key: interview-2026-10-13" \
  -H "Content-Type: application/json" \
  -d '{"upload":{"filename":"interview.m4a","size":48210334,"mime_type":"audio/mp4"},"language":"auto","diarize":true}'

201 응답에 awaiting_upload 상태의 작업과 전송에 필요한 upload 블록이 들어 있어요.

{
  "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
  "object": "transcription",
  "status": "awaiting_upload",
  "upload": {
    "chunk_url_template": "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/{index}",
    "headers": { "X-Upload-Token": "t1u_..." },
    "expires_at": "2026-10-13T10:30:00.000Z",
    "chunks": [
      { "index": 0, "offset": 0, "size": 8388608 },
      { "index": 1, "offset": 8388608, "size": 8388608 }
    ]
  }
}

서버가 파일을 약 8MiB(8,388,608바이트)씩 나눠 chunks 목록으로 알려 줘요. 위 예제는 목록의 일부만 보여 줘요. X-Upload-Token은 해당 업로드에만 쓰는 비밀 토큰이에요. 유효 기간은 1시간이며 만료 시각은 expires_at에 있어요.

2. 청크 전송하기

chunk_url_template의 {index}를 청크의 index로 바꾼 주소에 PUT 요청을 보내세요. 파일의 offset 위치에서 size 바이트를 읽어 본문에 넣고, Content-Type은 application/octet-stream으로 지정하세요. 청크 크기는 서버가 지정한 값과 정확히 같아야 해요. X-Upload-Token 헤더로 인증하므로 Authorization 헤더는 넣지 않아도 돼요.

curl -X PUT "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/0" \
  -H "X-Upload-Token: t1u_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @chunk-0.bin

청크를 받으면 { "object": "upload_chunk", "index": 0, "size": 8388608 } 형태로 응답해요. 같은 청크를 다시 보내면 기존 데이터를 교체해요. 크기나 인덱스가 서버의 목록과 맞지 않으면 422 invalid_request, 토큰이 없거나 만료됐으면 401 unauthorized를 반환해요.

3. 끊긴 업로드 이어서 올리기

GET /v1/transcriptions/:id/upload로 이미 도착한 청크를 확인하세요.

{
  "object": "upload",
  "status": "awaiting_upload",
  "total_bytes": 48210334,
  "uploaded_bytes": 16777216,
  "received_chunks": [0, 1],
  "chunks": [ { "index": 0, "offset": 0, "size": 8388608 } ],
  "expires_at": "2026-10-13T10:30:00.000Z"
}

received_chunks에 없는 청크만 추가로 전송하세요. 토큰이 만료됐으면 1단계 요청을 같은 Idempotency-Key와 같은 파라미터로 다시 보내세요. 새 작업을 만들지 않고 기존 작업과 새 업로드 토큰을 반환해요.

4. 업로드를 마치고 변환 시작하기

curl -X POST "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/complete" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"

POST /v1/transcriptions/:id/upload/complete를 호출하면 서버가 청크의 누락 여부와 크기를 확인해요. 모두 맞으면 파일을 합치고 변환 작업을 대기열에 넣은 뒤, 작업 객체와 함께 202를 반환해요. 빠진 청크가 있으면 409 upload_incomplete를 반환하고 missing_chunks에 다시 보낼 인덱스를 알려 줘요. 이미 업로드를 완료했거나 취소했다면 409 invalid_state를 반환해요.

업로드를 마친 뒤에는 GET /v1/transcriptions/:id?wait=60으로 상태를 조회하거나 웹훅으로 알림을 받으세요.

전체 흐름을 실행하는 Python 예제

import os
import requests
 
API = "https://api.transcript1.com"
auth = {"Authorization": f"Bearer {os.environ['TRANSCRIPT1_API_KEY']}"}
path = "interview.m4a"
 
created = requests.post(
    f"{API}/v1/transcriptions",
    headers={**auth, "Idempotency-Key": "interview-2026-10-13"},
    json={"upload": {"filename": os.path.basename(path), "size": os.path.getsize(path)}},
)
created.raise_for_status()
transcription = created.json()
upload = transcription["upload"]
 
with open(path, "rb") as file:
    for chunk in upload["chunks"]:
        file.seek(chunk["offset"])
        url = upload["chunk_url_template"].replace("{index}", str(chunk["index"]))
        response = requests.put(
            url,
            data=file.read(chunk["size"]),
            headers={**upload["headers"], "Content-Type": "application/octet-stream"},
        )
        response.raise_for_status()
 
done = requests.post(f"{API}/v1/transcriptions/{transcription['id']}/upload/complete", headers=auth)
done.raise_for_status()
print(done.json()["status"])

업로드 한도와 파일 보관 기간

  • 팀당 awaiting_upload 상태의 업로드는 동시에 20개까지 가능해요. 한도를 넘겨 생성하면 429 too_many_active_jobs와 Retry-After 헤더를 반환해요.
  • 생성 후 24시간 안에 업로드를 완료하지 않으면 작업을 취소하고 청크를 삭제해요.
  • 작업이 completed, failed, canceled 중 하나로 끝나면 24시간 뒤에 미디어 파일을 삭제해요. 스크립트는 DELETE /v1/transcriptions/:id로 직접 삭제할 때까지 남아요.
  • 파일 재생 시간이 확인되면 분 단위로 올림해 크레딧을 차감해요. 작업이 실패하거나 취소되면 비용이 들지 않아요. 자세한 기준은 요금제와 사용 한도를 확인하세요.

최근 업데이트 2026년 10월 14일