API reference
Upload sessions
7 operations. Base URL https://api.scarleta.ai. Select an operation to see its parameters, samples and errors.
Jump to an operation
GET/v1/audio/uploadsList unfinished upload sessions
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Returns your upload sessions that are still open, newest first (up to 200), so an interrupted upload can be found and resumed. Finished and cancelled sessions are not listed. Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge.
curl "https://api.scarleta.ai/v1/audio/uploads" \
-H "Authorization: Bearer $SCARLETA_API_KEY"Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| statusquery | "uploading" | Optional | Only `uploading` is supported, and it is the default. |
Response fields
| Field | Type | Description |
|---|---|---|
| sessions | array<object> | |
| sessions[].session_id | string | Identifier of the session. |
| sessions[].file_id | string | Identifier the file will have once completed. |
| sessions[].audio_id | string | |
| sessions[].filename | string | null | |
| sessions[].content_type | string | |
| sessions[].declared_bytes | integer | Size declared when the session was created. Allowed: -9007199254740991 to 9007199254740991. |
| sessions[].part_size_bytes | integer | Allowed: -9007199254740991 to 9007199254740991. |
| sessions[].part_count | integer | Allowed: -9007199254740991 to 9007199254740991. |
| sessions[].tags | array<string> | |
| sessions[].version_of | string | null | `audio_id` this upload will be attached to, if any. |
| sessions[].created_at | string | ISO 8601 timestamp. |
| sessions[].expires_at | string | ISO 8601 timestamp. |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | invalid_status | A `status` other than `uploading`. |
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | The database is temporarily unavailable. Retry shortly. |
Example responses
{
"data": {
"sessions": [
{
"session_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"file_id": "9e8d7c6b-5a49-4382-b170-6f5e4d3c2b1a",
"audio_id": "audio_bbb14949dc19",
"filename": "morning-session.wav",
"content_type": "audio/wav",
"declared_bytes": 1920044,
"part_size_bytes": 16777216,
"part_count": 1,
"tags": [
"morning"
],
"version_of": null,
"created_at": "2026-10-20T11:53:45.938Z",
"expires_at": "2026-10-27T11:53:45.938Z"
}
]
}
}- 200 Open sessions. The body is `{ data }` without `meta`.
- 400 A `status` other than `uploading`.
- 401 Missing, malformed, unknown or revoked API key.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 The database is temporarily unavailable. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.
POST/v1/audio/uploadsStart an upload session
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Starts a resumable upload for a file of any size up to 10 GiB (1 GiB for MP4 or MOV video). The file is sent in parts of part_size_bytes (16 MiB; the last part is smaller), at most 10000 parts. The flow is: create the session, ask for part URLs, PUT each part to its URL (parts can go in parallel and be retried), then complete the session. A session you do not finish can be resumed by reading its status, and is cleaned up 7 days after it started.
Creating a session reserves the declared size in your storage at once, so a file that would not fit is refused here with 413 storage_quota_exceeded. At most 50 sessions started in the last 60 minutes can be unfinished at the same time. If you send sha256, repeating the same request (same hash, filename, size and version_of) within 5 minutes returns the open session instead of starting a second one, which makes a lost response safe to retry. Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge; the file counts toward your storage.
curl -X POST "https://api.scarleta.ai/v1/audio/uploads" \
-H "Authorization: Bearer $SCARLETA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "morning-session.wav",
"content_type": "audio/wav",
"size_bytes": 1920044,
"tags": [
"morning"
],
"client_duration_seconds": 60
}'Request body
| Name | Type | Required | Description |
|---|---|---|---|
| filenamebody | string | Required | Name to show for the file, at most 255 characters. Required. Allowed: 1 to 255 characters. |
| content_typebody | string | Required | Content type of the file. Required. One of: `audio/wav`, `audio/wave`, `audio/x-wav`, `audio/mpeg`, `audio/mp3`, `audio/ogg`, `audio/flac`, `audio/aac`, `audio/m4a`, `audio/mp4`, `audio/x-m4a`, `audio/aiff`, `audio/x-aiff`, `audio/webm`, `audio/opus`, `audio/x-opus+ogg`, `video/mp4`, `video/quicktime`. |
| size_bytesbody | integer | Required | Size of the whole file in bytes. Required. At most 10 GiB for audio and 1 GiB for video. Allowed: at most 10737418240. |
| sha256body | string | Optional | SHA-256 of the file bytes as 64 hexadecimal characters. Optional; enables safe retry of this call. |
| tagsbody | array<string> | Optional | Tags to put on the file, at most 50 of at most 64 characters each. Blank tags are dropped and duplicates merged. |
| version_ofbody | string | Optional | `audio_id` of one of your ready files to attach this upload to as a new version, once it completes. Allowed: at most 200 characters. |
| client_duration_secondsbody | number | Optional | Length of the audio in seconds, if you know it. Display only; never used for billing. Allowed: at least 0. |
Response fields
| Field | Type | Description |
|---|---|---|
| session_id | string | Identifier of the session. |
| file_id | string | Identifier the file will have once completed. |
| audio_id | string | Library identifier of the file. |
| part_size_bytes | integer | Size of every part except the last. Allowed: -9007199254740991 to 9007199254740991. |
| part_count | integer | Number of parts to send. Allowed: -9007199254740991 to 9007199254740991. |
| parts_done | array<integer> | Part numbers already uploaded (empty for a new session). |
| expires_at | string | When an unfinished session is cleaned up, as an ISO 8601 timestamp. |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | missing_filename | A required field is missing or malformed, `tags`, `sha256` or the duration is invalid, or `version_of` is not one of your ready files. |
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 413 | file_too_large | The declared size is over the per-file limit, or the file does not fit in your storage (`storage_quota_exceeded`). |
| 429 | too_many_active_uploads | Too many unfinished sessions, or over the per-minute cap of these routes. |
| 503 | upload_unavailable | The session could not be registered; nothing was reserved. Retry shortly. |
Example responses
{
"data": {
"session_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"file_id": "9e8d7c6b-5a49-4382-b170-6f5e4d3c2b1a",
"audio_id": "audio_bbb14949dc19",
"part_size_bytes": 16777216,
"part_count": 1,
"parts_done": [],
"expires_at": "2026-10-27T11:53:45.938Z"
}
}- 201 Session created. The body is `{ data }` without `meta`.
- 400 A required field is missing or malformed, `tags`, `sha256` or the duration is invalid, or `version_of` is not one of your ready files.
- 401 Missing, malformed, unknown or revoked API key.
- 413 The declared size is over the per-file limit, or the file does not fit in your storage (`storage_quota_exceeded`).
- 429 Too many unfinished sessions, or over the per-minute cap of these routes.
- 503 The session could not be registered; nothing was reserved. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_content_type, invalid_duration, invalid_json, invalid_key_format, invalid_sha256, invalid_tags, invalid_version_of, missing_api_key, missing_auth, missing_size, rate_limit_exceeded, rate_limit_unavailable, storage_quota_exceeded, tag_too_long, too_many_tags, unauthorized.
GET/v1/audio/uploads/{sessionId}Get an upload session
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Returns the state of one session, with the parts storage has actually received, so an interrupted upload resumes by sending only the missing parts. Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge.
SESSIONID="YOUR_SESSIONID"
curl "https://api.scarleta.ai/v1/audio/uploads/$SESSIONID" \
-H "Authorization: Bearer $SCARLETA_API_KEY"Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| sessionIdpath | string | Required | The `session_id` returned when the session was created. |
Response fields
| Field | Type | Description |
|---|---|---|
| session_id | string | Identifier of the session. |
| file_id | string | Identifier the file has once completed. |
| audio_id | string | null | |
| status | "uploading" | "completed" | "aborted" | "expired" | `uploading` until completed or cancelled. |
| parts_done | array<integer> | Part numbers storage has received. |
| bytes_done | integer | Total size of those parts in bytes. Allowed: -9007199254740991 to 9007199254740991. |
| declared_bytes | integer | Allowed: -9007199254740991 to 9007199254740991. |
| part_size_bytes | integer | Allowed: -9007199254740991 to 9007199254740991. |
| part_count | integer | Allowed: -9007199254740991 to 9007199254740991. |
| filename | string | null | |
| expires_at | string | ISO 8601 timestamp. |
Errors
| Status | Code | Description |
|---|---|---|
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 404 | upload_session_not_found | No upload session with this id in your account. A session that belongs to another account is reported the same way. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | Storage or the database is temporarily unavailable. Retry shortly. |
Example responses
{
"data": {
"session_id": "7c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
"file_id": "9e8d7c6b-5a49-4382-b170-6f5e4d3c2b1a",
"audio_id": "audio_bbb14949dc19",
"status": "uploading",
"parts_done": [
1
],
"bytes_done": 1920044,
"declared_bytes": 1920044,
"part_size_bytes": 16777216,
"part_count": 1,
"filename": "morning-session.wav",
"expires_at": "2026-10-27T11:53:45.938Z"
}
}- 200 Session state. The body is `{ data }` without `meta`.
- 401 Missing, malformed, unknown or revoked API key.
- 404 No upload session with this id in your account. A session that belongs to another account is reported the same way.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 Storage or the database is temporarily unavailable. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.
POST/v1/audio/uploads/{sessionId}/abortCancel an upload session
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Cancels an unfinished session: the parts are discarded and the storage reserved for the file is released. Cancelling a session that is already cancelled succeeds again; one that already completed returns 409 session_not_uploading (delete the file instead). Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge.
SESSIONID="YOUR_SESSIONID"
curl -X POST "https://api.scarleta.ai/v1/audio/uploads/$SESSIONID/abort" \
-H "Authorization: Bearer $SCARLETA_API_KEY"Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| sessionIdpath | string | Required | The `session_id` returned when the session was created. |
Response fields
| Field | Type | Description |
|---|---|---|
| status | "aborted" |
Errors
| Status | Code | Description |
|---|---|---|
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 404 | upload_session_not_found | No upload session with this id in your account. A session that belongs to another account is reported the same way. |
| 409 | session_not_uploading | The session already completed. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | Storage or the database is temporarily unavailable. Retry shortly. |
Example responses
{
"data": {
"status": "aborted"
}
}- 200 The session is cancelled. The body is `{ data }` without `meta`.
- 401 Missing, malformed, unknown or revoked API key.
- 404 No upload session with this id in your account. A session that belongs to another account is reported the same way.
- 409 The session already completed.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 Storage or the database is temporarily unavailable. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.
POST/v1/audio/uploads/{sessionId}/completeComplete an upload session
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Assembles the uploaded parts into the file. Every part must be uploaded with the right size and the total must match the size you declared. The bytes are then checked: a file that is not audio is removed and refused with 415 not_audio. On success the file is ready in your library. Completing a session that already completed returns the same result, so the call is safe to retry.
Optionally add tags (merged with the ones from the start), change version_of, or give client_duration_seconds. Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge.
SESSIONID="YOUR_SESSIONID"
curl -X POST "https://api.scarleta.ai/v1/audio/uploads/$SESSIONID/complete" \
-H "Authorization: Bearer $SCARLETA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tags": [
"morning"
]
}'Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| sessionIdpath | string | Required | The `session_id` returned when the session was created. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| tagsbody | array<string> | Optional | Tags to put on the file, at most 50 of at most 64 characters each. Blank tags are dropped and duplicates merged. |
| version_ofbody | string | Optional | `audio_id` of one of your ready files to attach this upload to. A value that is not one of yours is ignored. Allowed: at most 200 characters. |
| client_duration_secondsbody | number | Optional | Length of the audio in seconds. Display only. Allowed: at least 0. |
Response fields
| Field | Type | Description |
|---|---|---|
| audio_id | string | Library identifier of the file. |
| file_id | string | Identifier of the file. |
| size_bytes | integer | Final size in bytes. Allowed: -9007199254740991 to 9007199254740991. |
| format | string | Detected audio format. |
| status | "ready" | |
| version_link | "linked" | "failed" | null | `linked` or `failed` when `version_of` was requested, otherwise `null`. |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | invalid_tags | `tags` or `client_duration_seconds` is invalid. |
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 404 | upload_session_not_found | No upload session with this id in your account. A session that belongs to another account is reported the same way. |
| 409 | parts_missing | A part is missing or has the wrong size, the parts add up to more than the declared size, or the session was cancelled or already ended another way. |
| 413 | file_too_large | The uploaded bytes exceed the per-file limit; the upload is cancelled. |
| 415 | not_audio | The assembled file is not a supported audio or video file; it is removed. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | Storage is temporarily unavailable. Retry shortly. |
Example responses
{
"data": {
"audio_id": "audio_bbb14949dc19",
"file_id": "9e8d7c6b-5a49-4382-b170-6f5e4d3c2b1a",
"size_bytes": 1920044,
"format": "wav",
"status": "ready",
"version_link": null
}
}- 200 The file is ready. The body is `{ data }` without `meta`.
- 400 `tags` or `client_duration_seconds` is invalid.
- 401 Missing, malformed, unknown or revoked API key.
- 404 No upload session with this id in your account. A session that belongs to another account is reported the same way.
- 409 A part is missing or has the wrong size, the parts add up to more than the declared size, or the session was cancelled or already ended another way.
- 413 The uploaded bytes exceed the per-file limit; the upload is cancelled.
- 415 The assembled file is not a supported audio or video file; it is removed.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 Storage is temporarily unavailable. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_duration, invalid_json, invalid_key_format, missing_api_key, missing_auth, part_size_mismatch, rate_limit_unavailable, session_not_uploading, size_mismatch, tag_too_long, too_many_tags, unauthorized, upload_reservation_missing.
POST/v1/audio/uploads/{sessionId}/part-urlsGet upload URLs for parts
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Returns one upload URL per requested part, at most 20 per call. Send each part's bytes with a PUT to its url, exactly as returned and with no API key (the URL is the credential), within 60 minutes. A part is exactly part_size_bytes long except the last one. A part can be sent again; the last copy wins. Ask again for fresh URLs if they expire. URLs are opaque: do not parse them. Capped at 60 requests per minute per account across the upload session routes and the duplicate check; these routes do not use up the hourly account request budget. Available to free and paid accounts.
Cost. Free of charge.
SESSIONID="YOUR_SESSIONID"
curl -X POST "https://api.scarleta.ai/v1/audio/uploads/$SESSIONID/part-urls" \
-H "Authorization: Bearer $SCARLETA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"part_numbers": [
1
]
}'Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| sessionIdpath | string | Required | The `session_id` returned when the session was created. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| part_numbersbody | array<integer> | Required | Parts to get URLs for, each between 1 and the session's `part_count`, at most 20 numbers. |
Response fields
| Field | Type | Description |
|---|---|---|
| urls | array<object> | |
| urls[].part_number | integer | Allowed: -9007199254740991 to 9007199254740991. |
| urls[].url | string | Where to `PUT` this part. Opaque; use it as returned. |
| urls[].expires_at | string | ISO 8601 timestamp. |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | invalid_part_numbers | `part_numbers` is empty, too long or has a number outside the session. |
| 401 | invalid_key | Missing, malformed, unknown or revoked API key. |
| 404 | upload_session_not_found | No upload session with this id in your account. A session that belongs to another account is reported the same way. |
| 409 | session_not_uploading | The session is already completed or cancelled. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | Part URLs could not be created. Retry shortly. |
Example responses
{
"data": {
"urls": [
{
"part_number": 1,
"url": "https://storage.example.com/uploads/part-1?signature=…",
"expires_at": "2026-10-21T04:40:00.000Z"
}
]
}
}- 200 One URL per requested part. The body is `{ data }` without `meta`.
- 400 `part_numbers` is empty, too long or has a number outside the session.
- 401 Missing, malformed, unknown or revoked API key.
- 404 No upload session with this id in your account. A session that belongs to another account is reported the same way.
- 409 The session is already completed or cancelled.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 Part URLs could not be created. Retry shortly.
Try it
Sends this request from your browser to https://api.scarleta.ai with your own key. The key stays in this page only (never saved or put in the address) and is cleared when you leave. Revoke any key you have shared.
Other error codes this operation can return: auth_unavailable, invalid_auth_format, invalid_json, invalid_key_format, missing_api_key, missing_auth, rate_limit_unavailable, unauthorized.
PUT/v1/audio/uploads/{sessionId}/parts/{n}Upload a part through the API
Free and paid accounts
- API key required
- Free and paid accounts
- No token cost
Fallback target of a part URL. When a URL from the part-urls route points at this API instead of at storage, send the part bytes to it exactly as returned: it already carries the one-time t token, which is the credential, so there is no API key. The request needs a Content-Length header (without one it is refused with HTTP 411 missing_content_length) and a body no larger than part_size_bytes. Most accounts receive storage URLs and never call this route.
Cost. Free of charge.
SESSIONID="YOUR_SESSIONID"
N="YOUR_N"
curl -X PUT "https://api.scarleta.ai/v1/audio/uploads/$SESSIONID/parts/$N" \
-H "Authorization: Bearer $SCARLETA_API_KEY" \
-H "Content-Type: audio/wav" \
--data-binary @./recording.wavParameters
| Name | Type | Required | Description |
|---|---|---|---|
| sessionIdpath | string | Required | The `session_id` of the session. |
| npath | string | Required | Part number, from 1 to the session's `part_count`. |
| tquery | string | Optional | One-time token. Already part of the URL that points here; leave it as returned. |
Response fields
| Field | Type | Description |
|---|---|---|
| part_number | integer | Allowed: -9007199254740991 to 9007199254740991. |
| etag | string | Opaque checksum of the stored part. |
Errors
| Status | Code | Description |
|---|---|---|
| 400 | invalid_part_number | The part number is not within the session, or the body is missing. |
| 403 | invalid_upload_token | The URL has expired, or the token is missing or wrong. |
| 409 | session_not_uploading | The session already completed or was cancelled. |
| 413 | part_too_large | The body is larger than `part_size_bytes`. |
| 429 | rate_limit_exceeded | Over the account request budget. Wait for the `Retry-After` header, then retry. |
| 503 | upload_unavailable | Storage or the database is temporarily unavailable. Retry shortly. |
Example responses
{
"data": {
"part_number": 1,
"etag": "a54357aff0632cce46d942af68356b38"
}
}- 200 The part is stored. The body is `{ data }` without `meta`.
- 400 The part number is not within the session, or the body is missing.
- 403 The URL has expired, or the token is missing or wrong.
- 409 The session already completed or was cancelled.
- 413 The body is larger than `part_size_bytes`.
- 429 Over the account request budget. Wait for the `Retry-After` header, then retry.
- 503 Storage or the database is temporarily unavailable. Retry shortly.
Try it
This operation uploads a file or binary body, which a browser form cannot build. Use the cURL sample.
Other error codes this operation can return: missing_body, missing_content_length, rate_limit_unavailable.