Wolvy DOCS

Guide · ingest & encoding

Upload by URL

You give Wolvy a link; Wolvy downloads the file, encodes every resolution, encrypts it for your plan and tells you when it is ready. Here is what the link must satisfy and how to follow the video from queued to ready.

Endpoint POST /v1/videos Scope videos:write
On this page

How ingest works#

  1. You send a URLWolvy checks it immediately — https, public address, reachable, a video, fits your storage — and answers 202 with a video id, or a 422 that says what is wrong.
  2. Wolvy downloads the fileA background worker fetches it, re-checking the address at download time. A failed download is retried; the third failure marks the video failed.
  3. Encoding and encryptionThe file becomes a resolution ladder, encrypted with Multi-DRM or ClearKey according to your plan. video.created fires when this starts.
  4. Playable, then readyOnce the first resolution exists the status is playable — viewers can watch. When every resolution is done it is ready and video.ready fires.

Source URL rules#

The rules exist because Wolvy fetches the URL from inside its own network. Each one is checked when you call the API, and again before the download — including on every redirect.

RuleDetailIf not
https onlyPort 443 or 8443.invalid_source_url
Public addressThe hostname — and every redirect hop — must resolve to public IPs. Private, loopback and reserved ranges are refused.source_not_allowed
Answers HEADWolvy probes with a HEAD request that must return 2xx.source_unreachable
Looks like videoIf a Content-Type is sent it must be video/*, application/octet-stream, application/mp4 or binary/octet-stream.unsupported_source_type
SizeUp to 20 GiB, and no larger than your available storage (when Content-Length is sent).source_too_large · insufficient_storage
RedirectsAt most 5.too_many_redirects
Stays upThe link must keep working until the download finishes — a large file can take a while. Don’t expire it in minutes.video.failed later

Create the video#

curl -X POST "https://api.wolvy.net/v1/videos" \
  -H "Authorization: Bearer $WOLVY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5b6f1c2e-9a0d-4f3e-8c71-2d4b6a9e0f13" \
  -d '{
    "source_url": "https://media.example.com/uploads/onboarding.mp4",
    "title": "Onboarding",
    "description": "Week one.",
    "folder_id": 7
  }'
FieldTypeDescription
source_urlREQUIREDstringThe https link, up to 2048 characters.
titlestringUp to 255 characters. Defaults to the file name in the URL.
descriptionstringFree text.
folder_idintegerAn existing folder. Create folders with POST /v1/folders.

The 202 response is the full video object with status: "queued". embed_url is already usable; duration, size_bytes and poster_url fill in when the video is ready.

The status lifecycle#

Step through it — the simulator shows what GET /v1/videos/{id}/status returns and which webhooks your server receives at each point.

LIFECYCLE_SIM.EXE
queuedprocessingplayableready

Accepted with 202. Wolvy is downloading your source URL.

GET /v1/videos/{id}/status

{
  "id": "a1b2c3d4e5f60718293a",
  "object": "video_status",
  "status": "queued",
  "duration": null,
  "size_bytes": 0,
  "updated_at": "2026-09-15T09:30:00+00:00"
}

What your server hears

  1. Your POST /v1/videos returned 202 · status: "queued"
StatusMeaningWebhook
queuedAccepted; the source is being downloaded.
processingHanded to encoding.video.created
playableThe first resolution is ready. Embeds already play.
readyAll resolutions encoded; duration, size and poster are set.video.ready
failedDownload or encoding failed. Failed encodes cannot be retried through the API — create the video again.video.failed

Poll or listen#

Simple

Poll the status endpoint

GET /v1/videos/{id}/status is deliberately tiny. Poll every 10–30 seconds from a background job and stop at ready or failed. Mind the 120 requests-per-minute key limit if you watch many uploads. Polling code.

Recommended

Listen for webhooks

Subscribe to video.ready and video.failed. Events are picked up by jobs that run every minute, so expect them within a minute or two. Set up webhooks.

Captions, chapters & moments#

Captions

WebVTT, one track per language_code. Send the file inline as content or as a source_url (max 5 MB, fetched with the same address checks as videos). Posting a language again replaces it. SRT is not accepted — convert it to WebVTT first.

curl -X POST "https://api.wolvy.net/v1/videos/a1b2c3d4e5f60718293a/captions" \
  -H "Authorization: Bearer $WOLVY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5b6f1c2e-9a0d-4f3e-8c71-2d4b6a9e0f13" \
  -d '{
    "language_code": "ar",
    "label": "العربية",
    "source_url": "https://media.example.com/captions/onboarding.ar.vtt"
  }'

Chapters

Named ranges on the progress bar, in whole seconds, never overlapping. The response is the whole list, sorted by start, with each chapter’s index.

curl -X POST "https://api.wolvy.net/v1/videos/a1b2c3d4e5f60718293a/chapters" \
  -H "Authorization: Bearer $WOLVY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5b6f1c2e-9a0d-4f3e-8c71-2d4b6a9e0f13" \
  -d '{
    "title": "Setting up",
    "start": 45,
    "end": 210
  }'

Moments

Single labelled points (“highlights” in the dashboard): {"label": "Live demo", "timestamp": 120}. Timestamps are unique per video; a clash is 409 moment_exists. Full reference: Moments.

Errors you’ll meet#

CodeStatusWhat to do
no_active_plan422The account has no active plan. Assign a plan in the dashboard (Billing).
insufficient_storage422The file (per its Content-Length) is larger than your available storage. Free space or upgrade.
invalid_source_url422Malformed, not https, or a port other than 443/8443 — at the URL or a redirect hop. Use a plain https URL.
source_not_allowed422The host resolves to a private or reserved address. Serve the file from a public host.
source_unreachable422DNS failed, the connection failed, or the server answered non-2xx (a HEAD for videos). Check the URL answers HEAD publicly. GET-only presigned URLs fail here.
unsupported_source_type422The server sent a Content-Type that is not video. Serve video/* or application/octet-stream.
source_too_large422Over 20 GiB for a video, or 5 MB for a caption. Compress or split the file.
too_many_redirects422More than 5 redirects. Link to the final URL.
folder_not_found400 / 404400 when a folder_id you sent is not yours; 404 on /v1/folders/{id}. Check the id with List folders.
unknown_parameter400A body field — or a query parameter on a list or date-range endpoint — this endpoint does not accept. param names it. Remove it. encryption, resolutions and keep_original are decided by your plan and settings.

A download that fails after the 202 does not produce an HTTP error — you learn about it from the status (failed) or the video.failed webhook, whose data.error explains what happened.

What Wolvy decides for you#

Three things you might expect to send are deliberately not request fields. Sending them returns 400 unknown_parameter rather than being silently ignored:

You might sendDecided byRead it from
encryptionYour plan — Multi-DRM or ClearKey.protection on Get plan
resolutionsAccount setting: Settings → Player → Video quality.available_resolutions on player settings
keep_originalAccount setting: Settings → Storage.keep_original on player settings