BetterVideo API
Privacy-first video enhancement as an API. Send a video by URL, we upscale / sharpen / restore it on GPU, and return a time-limited download link — never trained on, never sold, auto-deleted.
Get an API key → · Interactive API reference (try it live) →
Introduction
The BetterVideo API is a REST API. All requests go to:
https://api.bettervideo.io/v1
The job model is asynchronous: you submit a video, we process it on GPU, and you either poll for status or receive a signed webhook when it's done. All responses are JSON. Every request must be authenticated.
Authentication
Authenticate with a bearer token in the Authorization header:
Authorization: Bearer bv_live_xxxxxxxxxxxxxxxx
There are two kinds of key, created in your developer console:
| Key prefix | What it does |
|---|---|
bv_test_ | Sandbox — free mock processing. No GPU, no credits charged, no approval required. Use it to build and test your integration. |
bv_live_ | Live — real GPU enhancement, billed against your credit balance. Requires account approval (early access). |
Keys are shown once at creation and stored hashed — keep them secret and never embed them in client-side code.
Quickstart
Submit a video, wait for it to finish, and download the result — three calls:
Each command is a single line — copy with the button and paste as-is.
# 1) Submit a job
curl -X POST https://api.bettervideo.io/v1/jobs -H "Authorization: Bearer bv_test_your_key" -H "Content-Type: application/json" -d '{"video_url":"https://example.com/clip.mp4","resolution":"1080p"}'
# -> 201 { "id": "JOB_ID", "status": "queued", "sandbox": true, ... }
# 2) Poll until status is "done" (or use a webhook, below)
curl https://api.bettervideo.io/v1/jobs/JOB_ID -H "Authorization: Bearer bv_test_your_key"
# -> { "status": "done", ... }
# 3) Get a time-limited download link
curl https://api.bettervideo.io/v1/jobs/JOB_ID/result -H "Authorization: Bearer bv_test_your_key"
# -> { "download_url": "https://...", "expires_in": 3600, "retention": { ... } }
Sandbox & testing
Any request made with a bv_test_ key runs in a mock lane:
it returns a realistic response with "sandbox": true and
"credits_charged": 0, completes after a short delay, uses no GPU, and
charges nothing. Sandbox keys work immediately — no approval needed — so you can build
your full integration before going live. Switch to a bv_live_ key when
you're ready for real enhancement.
Job lifecycle
A job moves through these states:
queued -> running -> done
\-> error (you are auto-refunded)
Find out when a job finishes in one of two ways:
- Poll
GET /v1/jobs/{id}untilstatusisdoneorerror. - Webhook — pass a
webhook_urlwhen you create the job and we'll POST a signed event when it finishes (see Webhooks).
Input requirements
| Requirement | Detail |
|---|---|
| Source | A publicly reachable http(s) URL pointing directly at a video file. Internal/private addresses are blocked. |
| Formats | Common video containers and codecs — MP4 (H.264),
MOV, MKV, WebM, AVI, and similar. If we can't decode the file you get a
clear unreadable_video error. |
| Output | Enhanced MP4 (H.264). |
| Target resolution | 1080p or 4k. |
| Max length | 10 minutes (600 s). Longer is rejected
with video_too_long — before any charge. |
| Max file size | 2 GB. Larger is rejected with
video_too_large. |
We measure the real duration of your video server-side and bill on that — never on a value you send.
Webhooks
If you pass a webhook_url, we POST a JSON event when the job finishes:
{ "event": "job.completed", "job_id": "JOB_ID", "status": "done" }
Every webhook is signed. Verify the X-BetterVideo-Signature header — an
HMAC-SHA256 of the raw request body using your signing secret — before trusting it.
Idempotency
Send an Idempotency-Key header on POST /v1/jobs to make
retries safe. A repeated key returns the original job instead of creating — and
charging for — a duplicate. Recommended whenever a gateway or queue might retry.
Errors
Errors use a consistent envelope and standard HTTP status codes:
{ "error": { "code": "insufficient_credits", "message": "...", "type": "billing_error" } }
| Status | Meaning |
|---|---|
400 | Validation error — bad/missing field, unsupported
resolution, video_too_long, or video_too_large |
401 | Missing or invalid API key |
402 | Insufficient credits (top up or enable auto-recharge) |
403 | Account pending approval, or a Secure-tier feature on a Standard key |
404 | Job not found |
409 | Result requested before the job is done |
429 | Rate limit exceeded |
Rate limits
Limits are applied per API key. Polling status is the most permissive; job creation
is more restricted. If you exceed a limit you get 429 — back off and
retry. Submitting ~60 jobs/min and polling ~300/min are
comfortably within limits.
Endpoints
Account
Validate a key and return account info: plan, credit balance, sandbox flag, approval status, and per-minute pricing. Handy as an auth test.
Create a job
| Field | Type | Required | Notes |
|---|---|---|---|
video_url | string | yes | Public http(s) link to the source video |
resolution | string | yes | "1080p" or "4k" |
duration_seconds | integer | no | Optional hint; we auto-detect and bill on the real length |
webhook_url | string | no | We POST a signed completion event here |
{
"id": "1b9d...e4",
"status": "queued",
"resolution": "1080p",
"duration_seconds": 15,
"credits_charged": 45,
"sandbox": false,
"created_at": "2026-06-23T20:00:00Z",
"expires_at": "2026-07-23T20:00:00Z"
}
Get a job
Returns the current status and metadata. Poll this until status is
done or error.
Get the result
When the job is done, returns a signed download URL valid for one hour
(re-request any time for a fresh link), plus a retention reminder:
{
"download_url": "https://...",
"expires_in": 3600,
"retention": {
"auto_delete_at": "2026-07-23T20:00:00Z",
"delete_now": "DELETE /v1/jobs/{id}",
"reminder": "For maximum privacy, delete this job as soon as you've downloaded it."
}
}
Delete a job
Permanently deletes the original and enhanced files from our storage. On the Secure tier the response includes a signed deletion certificate. See Privacy & retention.
Deletion certificate Secure
Re-fetch the cryptographically signed proof that a job's files were destroyed. Works whether the job was deleted on demand or auto-deleted at retention.
Audit log Secure
A chain-of-custody log of recent events on your account (job created, completed, result accessed, deleted, …).
Pricing & limits
Pay-as-you-go, billed per second of processed video (to the cent). You're charged when a job is accepted and automatically refunded if it fails.
| Standard | Secure | |
|---|---|---|
| 1080p | $1.80 / min ($0.03/sec) | $3.60 / min ($0.06/sec) |
| 4K | $3.60 / min ($0.06/sec) | $7.20 / min ($0.12/sec) |
Privacy is identical on both tiers. Secure adds the proof & control layer: signed deletion certificates, an audit log, and configurable retention. Limits: 10-minute max length, 2 GB max file size. New accounts start with free sandbox credits.
Privacy & data retention
Your data is removed two ways:
- On demand — call
DELETE /v1/jobs/{id}anytime (recommended right after you download). We suggest deleting promptly, and the download response reminds you with the scheduled auto-delete date. - Automatically at 30 days — if you never delete, we permanently remove all files once the job passes its retention window. You don't have to do anything.
On the Secure tier, every deletion (on-demand or automatic) can be proven with a signed deletion certificate. We never train on, and never sell, your data.
Next steps
Create an API key → · Try the interactive reference → · OpenAPI spec →