Video API
Use the Video API to upload and manage video assets, captions, player settings, webhooks, and usage estimates.
View markdownBase URL and authentication
The API base URL is:
https://rabata.io/api/v1/video
Create a Video API key from Dashboard → Video → API keys. Send it as a Bearer token with every request:
curl https://rabata.io/api/v1/video/assets \
--header "Authorization: Bearer YOUR_VIDEO_API_KEY"
Keep the key in a secret manager and send it only over HTTPS. A missing, malformed, disabled, or unknown key returns 401 Unauthorized.
Requests are limited to 60 per minute for each authenticated account. A throttled request returns 429 Too Many Requests.
Errors
Successful requests return JSON. Errors use this shape:
{
"error": "A description of the problem"
}
Common statuses are:
| Status | Meaning |
|---|---|
400 |
The request could not be parsed. |
401 |
The Bearer token is missing or invalid. |
403 |
The account is blocked, the Video subscription is inactive, or a metered operation has no active card or spendable promotional credit. |
404 |
The requested resource does not exist in the authenticated account. |
422 |
A parameter, file, or resource state is invalid. |
429 |
The request limit was exceeded. |
503 |
A dependent storage service is temporarily unavailable. |
Resource identifiers are UUIDs. A valid UUID owned by another account is treated as not found.
Assets
List assets
GET /api/v1/video/assets?page=1&limit=20
page starts at 1. limit defaults to 20 and is constrained to 1–100.
{
"data": [
{
"id": "ASSET_UUID",
"title": "Product tour",
"status": "ready",
"original_filename": "tour.mp4",
"file_size": 73400320,
"duration": 83.4,
"width": 1920,
"height": 1080,
"thumbnail_url": "https://...",
"allowed_domains": ["example.com"],
"created_at": "2026-07-30T10:00:00Z",
"embed_url": "https://rabata.io/embed/ASSET_UUID",
"stream_url": "https://..."
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"pages": 1
}
}
Retrieve one asset with:
GET /api/v1/video/assets/ASSET_UUID
stream_url is returned only when the asset is ready and its owner has valid,
funded Video access. If metered access is paused because the account has no active
card, active legacy trial, or at least $0.01 of promotional credit remaining,
list and show
requests still return asset metadata but omit stream_url; embeds also refuse
playback. Mutating requests return 403 until funding is restored.
Upload an asset
Uploads go directly to object storage with presigned multipart URLs.
-
Create the asset and upload session:
curl https://rabata.io/api/v1/video/assets \ --request POST \ --header "Authorization: Bearer YOUR_VIDEO_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "title": "Product tour", "original_filename": "tour.mp4", "file_size": 73400320 }'file_sizeis in bytes. Supported extensions are.mp4,.mov,.avi,.mkv,.webm,.flv,.wmv,.m4v,.3gp, and.ogv. The maximum file size is 10 GB.The response contains the new asset
id, anupload.upload_id, theupload.chunk_size, and one presigned URL per part. -
Split the file into chunks of
upload.chunk_sizebytes.PUTeach chunk to the corresponding presigned URL in order, without the Rabata Authorization header. Save theETagresponse header from every upload. -
Complete the upload:
curl https://rabata.io/api/v1/video/assets/ASSET_UUID/confirm \ --request POST \ --header "Authorization: Bearer YOUR_VIDEO_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "upload_id": "UPLOAD_ID", "parts": [ { "part_number": 1, "etag": "PART_1_ETAG" }, { "part_number": 2, "etag": "PART_2_ETAG" } ] }'
The asset moves through waiting, uploaded, processing, and ready. Poll the asset or listen for an asset.ready webhook before using its stream URL. A response with transcoding_started: false includes a warning and can be retried.
If the upload cannot be completed, cancel its multipart session and discard the waiting asset:
POST /api/v1/video/assets/ASSET_UUID/abort
Content-Type: application/json
{
"upload_id": "UPLOAD_ID"
}
Cancellation remains available when the Video subscription has expired so abandoned storage uploads can still be cleaned up.
Update or delete an asset
Update the domain allowlist or asset-specific player settings:
curl https://rabata.io/api/v1/video/assets/ASSET_UUID \
--request PATCH \
--header "Authorization: Bearer YOUR_VIDEO_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"allowed_domains": ["example.com", "www.example.com"],
"player_settings": {
"accent_color": "#28CDD9",
"autoplay": false,
"muted": false,
"loop_video": false,
"show_controls": true,
"show_title": false
}
}'
An empty allowed_domains array allows embedding from any domain. At most 20 hostnames can be supplied; enter hostnames without paths.
Delete an asset with:
DELETE /api/v1/video/assets/ASSET_UUID
Deleting an asset removes it from the API and schedules its stored media for cleanup.
Get embed code
When the asset is ready:
GET /api/v1/video/assets/ASSET_UUID/embed
The response contains embed_url and a ready-to-use iframe string.
Manage a custom thumbnail
Request a presigned image upload:
POST /api/v1/video/assets/ASSET_UUID/thumbnail
Content-Type: application/json
{
"filename": "poster.jpg",
"content_type": "image/jpeg",
"file_size": 245760
}
Upload the image to the returned url, then confirm its returned storage key:
PUT /api/v1/video/assets/ASSET_UUID/thumbnail
Content-Type: application/json
{
"key": "RETURNED_STORAGE_KEY"
}
Remove the custom thumbnail with:
DELETE /api/v1/video/assets/ASSET_UUID/thumbnail
Captions
List or retrieve captions:
GET /api/v1/video/assets/ASSET_UUID/captions
GET /api/v1/video/assets/ASSET_UUID/captions/CAPTION_UUID
Upload a WebVTT or SubRip file as multipart form data:
curl https://rabata.io/api/v1/video/assets/ASSET_UUID/captions \
--request POST \
--header "Authorization: Bearer YOUR_VIDEO_API_KEY" \
--form "file=@captions.vtt" \
--form "label=English" \
--form "language=en"
Caption files can be up to 2 MB. Language values use a lowercase BCP 47 tag such as en, en-us, or pt-br. Each asset can have one active caption per language and up to 30 captions.
Delete a caption with:
DELETE /api/v1/video/assets/ASSET_UUID/captions/CAPTION_UUID
Player defaults
Get the account-wide player defaults:
GET /api/v1/video/player_config
Update any subset of the settings:
PATCH /api/v1/video/player_config
Content-Type: application/json
{
"accent_color": "#28CDD9",
"autoplay": false,
"muted": false,
"loop_video": false,
"show_controls": true,
"show_title": false
}
Asset-specific player settings override these account defaults.
Analytics
Get views and watch-time totals plus a time series:
GET /api/v1/video/assets/ASSET_UUID/analytics?from=2026-07-01&to=2026-07-30&granularity=day
granularity can be day or hour; it defaults to day. from defaults to 30 days ago and to defaults to now.
Get the audience-retention curve for the same period:
GET /api/v1/video/assets/ASSET_UUID/retention?from=2026-07-01&to=2026-07-30
Usage and pricing
Retrieve the current calendar month's completed usage and estimated charges:
GET /api/v1/video/usage
The existing data array remains unchanged for clients that consume current-period usage records. The additive summary object contains the usage-pricing contract:
{
"data": [
{
"period_start": "2026-07-31T00:00:00Z",
"period_end": "2026-07-31T23:59:59Z",
"storage_bytes": 1200000000,
"egress_bytes": 410000000
}
],
"summary": {
"period_start": "2026-07-01",
"period_end": "2026-07-31",
"data_through": "2026-07-30",
"currency": "usd",
"source_storage": {
"current_bytes": 1200000000,
"average_bytes": "1000000000.000000",
"rate_per_gb_month": "0.006000",
"estimated_cost": "0.0060"
},
"delivery": {
"720p": {
"seconds": "6000.000",
"minutes": "100.0",
"rate_per_minute": "0.000600",
"estimated_cost": "0.0600"
},
"1080p": {
"seconds": "0.000",
"minutes": "0.0",
"rate_per_minute": "0.000800",
"estimated_cost": "0.0000"
},
"2k": {
"seconds": "0.000",
"minutes": "0.0",
"rate_per_minute": "0.001300",
"estimated_cost": "0.0000"
},
"4k": {
"seconds": "0.000",
"minutes": "0.0",
"rate_per_minute": "0.002500",
"estimated_cost": "0.0000"
}
},
"estimated_total": "0.0700",
"transcoding": {
"standard_on_demand_included": true
}
}
}
delivery always contains the 720p, 1080p, 2k, and 4k rate tiers. data_through is the last contiguous completed UTC day, or null when no day is ready. Current-month values are estimates; invoice charges are finalized only after every billable day in the month is complete.
Webhooks
Create a public HTTP or HTTPS callback for any combination of asset.created, asset.ready, asset.errored, and asset.deleted. Use HTTPS in production:
curl https://rabata.io/api/v1/video/webhooks \
--request POST \
--header "Authorization: Bearer YOUR_VIDEO_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"callback_url": "https://example.com/rabata-webhooks",
"events": ["asset.ready", "asset.errored"]
}'
The callback hostname must resolve only to public IP addresses. An empty events array subscribes to all supported events.
The create response returns the signing secret once; store it in your secret manager because later responses do not expose it.
List, retrieve, update, or delete webhook configurations with:
GET /api/v1/video/webhooks
GET /api/v1/video/webhooks/WEBHOOK_UUID
PATCH /api/v1/video/webhooks/WEBHOOK_UUID
DELETE /api/v1/video/webhooks/WEBHOOK_UUID
Delivery requests use Content-Type: application/json, identify the event in X-Rabata-Event, and include an HMAC-SHA256 digest in X-Rabata-Signature. Respond with a 2xx status after accepting the event. Failed deliveries are retried with backoff.