Upload a File
Upload an audio or video file from your machine to start a transcription job. Use it when the file has no public URL. The upload host, upload.speechischeap.com, stores the file and forwards it to the Jobs API as a job from a URL. It returns the same job, so webhooks, streaming, polling, and cancellation work as they do for any other job.
Endpoint
POST https://upload.speechischeap.com/v2/jobs/
Send the request to upload.speechischeap.com, not to api.speechischeap.com. The API host reads a JSON body and doesn't accept files.
Authentication
Send your API key as a Bearer token. Upload checks the key with the Jobs API before it reads the file.
Authorization: Bearer YOUR_API_KEY
Request
Send a multipart/form-data body. Name the file part input_file, and send every other parameter as a form field.
| Parameter | Type | Default | Description |
|---|---|---|---|
input_file | file | Required | The audio or video file to transcribe. The file can be up to 2 GiB. See Uploads for the other rules. |
can_label_audio, can_parse_speakers, can_parse_words | boolean | false | The add-ons. Send true to turn one on. See Output and Add-ons for their output and pricing for their price. |
can_stream_output | boolean | false | When enabled, streams the transcription after the upload finishes. See Stream Progress. |
webhook_url | string | "" | The URL that receives the job's result in a single POST request. See Webhooks. |
| Other parameters | Every other parameter of Create a Job from a URL works as a form field, except input_url. |
Example Requests
Upload and Receive a Webhook
curl --request POST \
--url https://upload.speechischeap.com/v2/jobs/ \
--header 'Authorization: Bearer YOUR_API_KEY' \
--form 'input_file=@/path/to/audio-file.mp3' \
--form 'webhook_url=https://your-domain.com/webhook' \
--no-buffer
The --no-buffer option prints each event as it arrives.
Upload and Stream the Result
curl --request POST \
--url https://upload.speechischeap.com/v2/jobs/ \
--header 'Authorization: Bearer YOUR_API_KEY' \
--form 'input_file=@/path/to/audio-file.mp3' \
--form 'can_stream_output=true' \
--no-buffer
Response
Upload answers every valid request with 200 OK and Content-Type: text/event-stream, even when the job doesn't stream. A request that fails validation gets one of the other statuses and a JSON body with an error or message field.
| Status Code | Description |
|---|---|
| 200 OK | Upload accepted the file and started the event stream. |
| 400 Bad Request | The input_file part is missing or misnamed, the file's type isn't supported, or the upload ended before the whole file arrived. |
| 401 Unauthorized | The Authorization header is missing or malformed, or the API key is unknown, revoked, or its billing isn't active. |
| 406 Not Acceptable | The body is JSON, plain text, or empty instead of multipart/form-data. |
| 415 Unsupported Media Type | The body has another Content-Type, such as application/x-www-form-urlencoded, or none. Upload answers before it checks the API key. |
| 500 Internal Server Error | Upload failed before it started the stream. |
Each event is a line that starts with data: and holds one JSON object, followed by a blank line.
Upload Events
The stream starts with upload events. bytes_uploaded is the number of bytes stored so far.
data: {"type":"upload","message":"Uploading...","bytes_uploaded":0}
data: {"type":"upload","message":"Uploading...","bytes_uploaded":16384}
Job Event
When the file is stored, Upload creates the job. Without can_stream_output, the last event is the job, the same one that creating a job from a URL returns, and the stream closes:
data: {"status":"PENDING","id":"00000000-1111-7222-b333-444444444444-sic","output":{}}
With can_stream_output, the stream continues with the job's initial, progress, segment, and final events. See Stream Progress.
Error Events
A failure after the stream starts can't change the HTTP status, so it arrives as an event, and the stream closes:
data: {"status":"error","error":"Upload connection closed"}
Errors
Errors before the stream starts are JSON, and the most likely are Unsupported file type detected: <type>. and Missing required "input_file" parameter. Errors after it starts arrive as error events, such as API call failed: 400 - Input URL is not reachable, and Upload errors explains each one.
Notes
- Upload accepts a file by its content, but it keeps the extension from the file name. Name the file with a supported extension. A file named
audio.m4boraudiopasses the content check and then fails. See Uploads for the size limit, the accepted types, the naming rule, and how long Upload keeps the file. - You pay only when a job completes. See Billing.
- The upload host accepts browser requests (CORS), but browser code exposes your API key to anyone who loads the page. Send uploads from a server, or use a key you can revoke.
- To pay with a crypto wallet instead of an API key, see x402 Upload a File.