Upload API (SDK)

Create a job, upload bytes to a presigned URL, then complete. This is what the official SDKs call.

Create job

POST/api/v1/upload
bash
curl -X POST "https://api.speechrevolutions.com/api/v1/upload" \
  -H "X-API-Key: $SPEECHREVOLUTIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_size": 1048576,
    "output_type": "json",
    "word_timestamps": true,
    "speaker_labels": true,
    "nltk": true,
    "tier": "standard",
    "custom_vocabulary": ["AcmeCorp"]
  }'

Request body

FieldTypeDefault
file_sizeintrequired (unless audio_url)
audio_urlstring (uri)alternative to file_size
output_typestringjson
word_timestampsbooltrue
speaker_labelsbooltrue
nltkbooltrue
tierstringstandard — the only tier currently available
custom_vocabularystring[]optional
callback_urlstring (uri)optional

Provide exactly one of file_size or audio_url. With audio_url (an http(s) URL) the platform fetches the audio itself: the response has no upload_url, the job is enqueued immediately, and you skip the upload and /upload/complete steps entirely — go straight to waiting on the job stream. The URL must resolve to a public host.

callback_url is an optional http(s) webhook. On completion or permanent failure the platform POSTs a JSON notification there, shaped like {job_id, status: "completed"|"failed", download_url?, step?, reason?}, with these headers:

HeaderValue
X-SR-Signaturesha256=<hex>, an HMAC-SHA256 of the raw request body. Verify it against the exact bytes you received, with a constant-time comparison.
X-SR-Eventcompleted or failed, the same value as status in the body, so you can route a delivery before parsing it.
X-SR-DeliveryA unique id for this delivery. Retries of the same delivery reuse it, so use it to ignore duplicates.
User-AgentSpeechRevolutions-Webhook/1

Respond with any 2xx to acknowledge. A 5xx, a timeout (10 seconds per attempt) or a connection error is retried with backoff, up to 4 attempts in all; a 4xx is treated as final and not retried. See any SDK page for a signature-verification snippet.

Response

json
{
  "job_id": "…",
  "upload_url": "https://…",   // null for audio_url jobs (nothing to upload)
  "download_url": "https://…",
  "content_type": "application/octet-stream",
  "expires_in": 3600
}

Progress heartbeat

POST/api/v1/upload/progress

Ping while the PUT is in flight (TTL ~15s). Body: {"job_id":"…"}

Complete

POST/api/v1/upload/complete

Enqueues the job. Body: {"job_id":"…"}

Then wait on GET /api/v1/jobs/{job_id}/stream.

Multipart upload (large files)

An alternative to the single presigned PUT: upload the file in parts, which is more resilient for large files. The official SDKs use this by default and fall back to the single-shot PUT above if it's unavailable. The single-shot flow is always supported.

Create

POST/api/v1/upload/multipart/create

Same body as /upload (needs file_size), plus an optional part_size. Returns presigned URLs for each part:

json
{
  "job_id": "…",
  "upload_id": "…",
  "download_url": "https://…",
  "part_size": 16777216,
  "num_parts": 3,
  "parts": [
    { "part_number": 1, "url": "https://…" },
    { "part_number": 2, "url": "https://…" },
    { "part_number": 3, "url": "https://…" }
  ],
  "expires_in": 3600
}

PUT each part's bytes to its url and keep the ETag from each response header.

Complete

POST/api/v1/upload/multipart/complete

Finalizes the upload and enqueues the job. Body: {"job_id": "…", "parts": [{"part_number": 1, "etag": "…"}, …]}

Abort

POST/api/v1/upload/multipart/abort

Discards an in-progress multipart upload. Body: {"job_id": "…"}