Video API

Use the Video API to upload and manage video assets, captions, player settings, webhooks, and usage estimates.

View markdown

Base 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.

  1. 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_size is 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, an upload.upload_id, the upload.chunk_size, and one presigned URL per part.

  2. Split the file into chunks of upload.chunk_size bytes. PUT each chunk to the corresponding presigned URL in order, without the Rabata Authorization header. Save the ETag response header from every upload.

  3. 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.