API reference
Endpoints, request fields, job states, and failure codes for the Automation API.
The tscaps automation API is organized around RESTful JSON endpoints. Send your secret API key as a bearer token in the Authorization header with every request:
Authorization: Bearer TSCAPS_API_KEY
Content-Type: application/json
Base URL:
https://api.tscaps.io
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/v1/automation-jobs |
Create a job |
GET |
/v1/automation-jobs/:id |
Get job status |
POST |
/v1/automation-jobs/:id/cancel |
Cancel a job |
POST |
/v1/automation-jobs/uploads |
Create an upload URL |
GET |
/v1/automation-jobs |
List jobs |
Create a job
POST /v1/automation-jobs
Queues a new video processing job with caption styling and subtitle burn-in.
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
videoUrl |
string | One source | Publicly accessible HTTPS URL of the video file to process. Specify either videoUrl or uploadId, never both. |
uploadId |
string | One source | ID of a file uploaded via POST /v1/automation-jobs/uploads. Specify either videoUrl or uploadId, never both. |
templateId |
string | Yes | ID of the caption template to apply. Use built-in templates (such as mira or noor) or custom templates saved to your account. View all available templates in your Templates catalog. |
format |
string | No | Output video container: mp4 or webm. Defaults to mp4. |
quality |
string | No | Encoding bitrate quality: low, medium, or high. Defaults to high. Selecting higher quality does not change minute consumption. |
resolution |
object | No | Output dimensions in pixels as { "width": number, "height": number }. Must not exceed your plan’s frame budget. Omit to preserve the source resolution (automatically downscaled if over budget). |
language |
string | No | Language spoken in the video as a 2-letter ISO/BCP-47 code (e.g., en, es, fr). Automatically detected if omitted. |
webhookUrl |
string | No | Public HTTPS URL where an event notification will be sent when the job reaches a terminal state (succeeded, failed, or cancelled). |
Request example
{
"videoUrl": "https://example.com/reel.mp4",
"templateId": "mira",
"format": "mp4",
"quality": "high",
"resolution": { "width": 1080, "height": 1920 },
"language": "en",
"webhookUrl": "https://api.yourdomain.com/webhooks/tscaps"
}
Code example
curl -X POST https://api.tscaps.io/v1/automation-jobs \
-H "Authorization: Bearer $TSCAPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"videoUrl": "https://example.com/reel.mp4",
"templateId": "mira",
"quality": "high"
}'
const response = await fetch("https://api.tscaps.io/v1/automation-jobs", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TSCAPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
videoUrl: "https://example.com/reel.mp4",
templateId: "mira",
quality: "high",
}),
});
const job = await response.json();
import os
import requests
response = requests.post(
"https://api.tscaps.io/v1/automation-jobs",
headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
json={
"videoUrl": "https://example.com/reel.mp4",
"templateId": "mira",
"quality": "high",
},
)
job = response.json()
Response
Returns 202 Accepted with the initial job record.
{
"id": "9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
"status": "queued",
"phase": "queued",
"templateId": "mira",
"quotedSeconds": null,
"format": "mp4",
"quality": "high",
"resolution": null,
"percent": null,
"downloadUrl": null,
"outputExpiresAt": null,
"failureReason": null,
"failureCode": null,
"settledAt": null,
"createdAt": "2026-09-12T10:11:38.000Z"
}
Get job status
GET /v1/automation-jobs/:id
Retrieves the current status and rendering progress of a specific job.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The unique UUID of the automation job. |
Code example
curl https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610 \
-H "Authorization: Bearer $TSCAPS_API_KEY"
const response = await fetch("https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610", {
headers: { Authorization: `Bearer ${process.env.TSCAPS_API_KEY}` },
});
const job = await response.json();
import os
import requests
response = requests.get(
"https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
)
job = response.json()
Response
Returns 200 OK with the complete job record.
{
"id": "9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
"status": "succeeded",
"phase": "succeeded",
"templateId": "mira",
"quotedSeconds": 74,
"format": "mp4",
"quality": "high",
"resolution": { "width": 1080, "height": 1920 },
"percent": null,
"downloadUrl": "https://storage.tscaps.io/outputs/9f2c48e1-...?token=...",
"outputExpiresAt": "2026-09-19T10:14:00.000Z",
"failureReason": null,
"failureCode": null,
"settledAt": "2026-09-12T10:12:52.000Z",
"createdAt": "2026-09-12T10:11:38.000Z"
}
Job lifecycle properties
status: High-level execution state. One of:queued: Waiting in queue for processing capacity.running: Actively processing.succeeded: Video rendered and available for download.failed: Job encountered an unrecoverable error.cancelled: Job was cancelled by user request.
phase: Detailed operation currently in progress:queued,ingesting,transcribing,rendering,succeeded,failed, orcancelled.percent: Integer between 0 and 100 indicating rendering progress during therenderingphase.nullin other phases.quotedSeconds: Measured duration of the input video in seconds (populated after ingest).downloadUrl: Presigned HTTPS download link to the final video (populated uponsucceeded).outputExpiresAt: ISO timestamp whendownloadUrlexpires (rendered files remain available for 7 days).
Cancel a job
POST /v1/automation-jobs/:id/cancel
Cancels a queued or currently executing job. If the job is active, rendering stops immediately. All minutes reserved for the job are refunded back to your account balance.
This endpoint is idempotent: repeating the cancel call on an already cancelled job returns 200 OK.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The unique UUID of the job to cancel. |
Code example
curl -X POST https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610/cancel \
-H "Authorization: Bearer $TSCAPS_API_KEY"
const response = await fetch("https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610/cancel", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TSCAPS_API_KEY}` },
});
const job = await response.json();
import os
import requests
response = requests.post(
"https://api.tscaps.io/v1/automation-jobs/9f2c48e1-5b7a-4a29-8874-9dfc8227b610/cancel",
headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
)
job = response.json()
Response
Returns 200 OK with the cancelled job record (status: "cancelled").
Create an upload URL
POST /v1/automation-jobs/uploads
Requests a signed URL to upload a video file directly to tscaps cloud storage when the video cannot be exposed over a public URL.
Request parameters
| Field | Type | Required | Description |
|---|---|---|---|
fileName |
string | Yes | Original file name (e.g., reel.mp4). Used to determine media content type. |
sizeBytes |
integer | Yes | Exact file size in bytes. This value is cryptographically signed into the presigned URL. |
Request example
{
"fileName": "reel.mp4",
"sizeBytes": 14205000
}
Code example
curl -X POST https://api.tscaps.io/v1/automation-jobs/uploads \
-H "Authorization: Bearer $TSCAPS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "fileName": "reel.mp4", "sizeBytes": 14205000 }'
const response = await fetch("https://api.tscaps.io/v1/automation-jobs/uploads", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TSCAPS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ fileName: "reel.mp4", sizeBytes: 14205000 }),
});
const upload = await response.json();
import os
import requests
response = requests.post(
"https://api.tscaps.io/v1/automation-jobs/uploads",
headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
json={"fileName": "reel.mp4", "sizeBytes": 14205000},
)
upload = response.json()
Response
Returns 201 Created with upload instructions:
{
"uploadId": "3b71d39a-7c22-48a3-92f1-47fae3223019",
"uploadUrl": "https://storage.tscaps.io/uploads/3b71d39a-...?signature=...",
"contentType": "video/mp4",
"sizeBytes": 14205000,
"expiresAt": "2026-09-12T10:26:38.000Z"
}
Upload the file binary to uploadUrl via HTTP PUT with the returned Content-Length and Content-Type. Once uploaded, pass uploadId to POST /v1/automation-jobs. Read the Direct file uploads guide for complete examples.
List jobs
GET /v1/automation-jobs
Retrieves a paginated list of recent automation jobs for your account, ordered newest first.
Query parameters
| Parameter | Type | Description |
|---|---|---|
cursor |
string | Opaque pagination cursor. Pass nextCursor from the previous response to retrieve the next page. |
Code example
curl "https://api.tscaps.io/v1/automation-jobs?cursor=eyJjcmVhdGVkQXQiOi..." \
-H "Authorization: Bearer $TSCAPS_API_KEY"
const response = await fetch("https://api.tscaps.io/v1/automation-jobs", {
headers: { Authorization: `Bearer ${process.env.TSCAPS_API_KEY}` },
});
const { jobs, nextCursor } = await response.json();
import os
import requests
response = requests.get(
"https://api.tscaps.io/v1/automation-jobs",
headers={"Authorization": f"Bearer {os.environ['TSCAPS_API_KEY']}"},
)
data = response.json()
jobs = data["jobs"]
next_cursor = data["nextCursor"]
Response
Returns 200 OK:
{
"jobs": [
{
"id": "9f2c48e1-5b7a-4a29-8874-9dfc8227b610",
"status": "succeeded",
"phase": "succeeded",
"templateId": "mira",
"quotedSeconds": 74,
"format": "mp4",
"quality": "high",
"resolution": { "width": 1080, "height": 1920 },
"percent": null,
"downloadUrl": "https://...",
"outputExpiresAt": "2026-09-19T10:14:00.000Z",
"failureReason": null,
"failureCode": null,
"settledAt": "2026-09-12T10:12:52.000Z",
"createdAt": "2026-09-12T10:11:38.000Z"
}
],
"nextCursor": null
}
Failure codes
When a job fails, the response includes:
failureCode: A machine-readable identifier for program logic.failureReason: A human-readable description for debugging or logging.
Always branch on failureCode in your application and include a generic fallback for any future codes:
| Failure Code | Meaning | Retryable | Resolution |
|---|---|---|---|
source-unreachable |
The video URL could not be reached or returned HTTP 4xx/5xx. | Yes | Check that the URL is public, unauthenticated, and online. |
source-unreadable |
The file was downloaded but could not be parsed as a valid video container. | No | Ensure the file is an encoded MP4, WebM, MOV, or supported container. |
source-too-long |
The video exceeds your plan’s maximum duration limit (3 min Free, 5 min Starter, 10 min Pro). | No | Shorten the video or upgrade your subscription plan. |
output-larger-than-source |
The requested resolution is larger than the input video dimensions. |
No | Tscaps does not upscale. Omit resolution or specify equal or smaller dimensions. |
automation-minutes-exhausted |
The account has insufficient automation minutes to process the video. | No | Buy more minutes or wait for monthly renewal. |
ingest-failed |
Audio extraction or preliminary video probing failed. | Yes | Check video codec compatibility or retry the request. |
transcription-failed |
Speech-to-text recognition encountered an error. | Yes | Retry the job. If speech is in a specific language, pass the language code explicitly. |
render-failed |
The rendering engine could not composite the subtitle frames. | Yes | Transient rendering error; retry the job. |
timed-out |
Processing exceeded the maximum execution deadline. | Yes | Retry the job. If the problem persists, reduce video duration. |
internal |
An unexpected server error occurred. | Yes | Transient error; safe to retry. |
Billing guarantee
Failed and cancelled jobs never consume automation minutes. Reserved minutes are refunded to your balance immediately.