REST API
Base URL https://api.ollanode.com. JSON in, JSON out. Every resource is scoped to your project by the credential you present.
Authentication
Send a bearer token on every authenticated call โ either a session token from /v1/auth/login (12h) or an API key (vbk_โฆ) from Settings โ API Keys.
Authorization: Bearer <session-token-or-api-key>
# or
x-api-key: vbk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Scopes โ read (GET), write (create/modify), admin (keys, team, audit). A 401 means a missing/invalid credential; a 403 means the credential lacks the required scope.
Authentication
Exchange credentials for a session token, or manage your own account. Session tokens last 12h; use them (or an API key) as a bearer on every other call.
/v1/auth/signup public Self-serve sign up. Creates a user + a project and sends a verification email.
Body { "email", "username", "password", "full_name"?, "project_name"? }
Returns { token, expires_at, user }
/v1/auth/login public Exchange username + password for a session token.
Body { "username", "password" }
Returns { token, expires_at, user }
/v1/auth/me bearer The authenticated user.
Returns UserView
/v1/auth/forgot-password public Email a password-reset link. Always returns 200 (no account enumeration).
Body { "email" }
/v1/auth/reset-password public Set a new password using the emailed token.
Body { "token", "new_password" }
/v1/auth/verify-email public Confirm an email address with the emailed token.
Body { "token" }
/v1/auth/resend-verification bearer Re-send the verification email.
/v1/auth/change-password bearer Change your password.
Body { "current_password", "new_password" }
/v1/account bearer Your account profile.
/v1/account bearer Update your profile.
Body { "full_name"? }
API keys
Machine credentials for server-to-server use. The full key (vbk_โฆ) is shown once at creation โ store it securely. Scopes: read, write, admin.
/v1/api-keys admin Create a key. Response includes the secret once.
Body { "name", "scopes": ["read","write","admin"] }
Returns { id, name, prefix, scopes, key }
/v1/api-keys admin List keys (no secrets).
/v1/api-keys/:id admin Revoke a key immediately.
Videos
Create a video record, attach a source (upload or remote URL), then poll status until "ready". Statuses: created โ uploading โ processing โ ready (or failed).
/v1/videos write Create a video. Pass source_url to ingest from the web automatically, or upload next.
Body { "title"?, "source_url"?, "playback_policy"? ("signed"|"public"), "max_height"?, "quality_preset"? ("low"|"standard"|"high"), "metadata"? }
Returns VideoView
/v1/videos read List videos (newest first). Query: ?limit, ?status.
/v1/videos/:id read Full video record.
/v1/videos/:id write Update title, playback_policy, or metadata.
Body { "title"?, "playback_policy"?, "metadata"? }
/v1/videos/:id write Delete the video and all its assets.
/v1/videos/:id/status read Lightweight status poll: { id, status, error_reason? }.
/v1/videos/:id/assets read Rendition ladder + asset metadata (heights, bitrates, sizes).
/v1/videos/:id/clip write Create a sub-clip as a new video.
Body { "start", "end", "title"? }
/v1/videos/:id/chapters write Set chapter markers.
Body { "chapters": [{ "start_seconds", "title" }] }
/v1/videos/:id/views read View counts / play analytics for the video.
/v1/videos/:id/download read Presigned URL to download the original/source.
Upload
Direct-to-storage uploads. Request a presigned URL, PUT the bytes straight to storage (no proxy), then mark the upload complete to start processing.
/v1/videos/:id/upload-url write Mint a single-shot presigned PUT URL.
Body { "content_type"? }
Returns { url, source_key, expires_in }
/v1/videos/:id/multipart write Begin a multipart upload for large files.
Body { "content_type"? }
/v1/videos/:id/upload-complete write Signal bytes are uploaded; transcoding begins.
Body { "source_key"?, "size_bytes"? }
Playback & media
When status is "ready", request a playback URL. Signed videos return a short-lived token; public videos do not. Or drop in the hosted <iframe> player.
/v1/videos/:id/playback read HLS master URL (+ token for signed), poster, subtitles.
Returns { master_url, token?, policy, expires_at, poster_url?, subtitles[] }
/v1/videos/:id/thumbnails read Generated thumbnails (presigned URLs).
/v1/videos/:id/thumbnail?t=SECONDS read Thumbnail nearest a timestamp.
/v1/videos/:id/transcript read Transcript status + VTT/SRT URLs + segments.
/v1/videos/:id/subtitles write Add a subtitle track (WebVTT).
Body { "language", "label"?, "content" }
/v1/videos/:id/subtitles read List subtitle tracks.
/v1/videos/:id/subtitles/:lang write Remove a subtitle track.
/embed/:id?token=โฆ public Hosted HLS player (iframe-embeddable). Token required for signed videos.
CDN pull zones
Map a hostname to an origin (or a storage zone) and serve it cached from the edge. Supports hotlink-protection (signed URLs), CORS, granular purge, traffic analytics, and edge rules.
/v1/zones write Create a pull zone. Use origin_url OR storage_zone_id.
Body { "hostname", "origin_url"?, "storage_zone_id"?, "default_ttl_secs"?, "cache_bypass"?[], "signed"?, "cors"? }
Returns ZoneView (token_secret shown once if signed)
/v1/zones read List zones.
/v1/zones/:id read Zone detail incl. edge rules.
/v1/zones/:id write Update origin, TTL, cache-bypass, CORS, active, signing, or rules.
Body { "origin_url"?, "default_ttl_secs"?, "cache_bypass"?, "cors"?, "active"?, "signed"?, "rules"? }
/v1/zones/:id write Delete the zone.
/v1/zones/:id/purge write Purge cache. Empty body = full purge; pass paths for granular.
Body { "paths"?: ["/file.m3u8"] }
/v1/zones/:id/rotate-token write Rotate the hotlink signing secret (returned once).
/v1/zones/:id/analytics read Live edge traffic: requests, egress bytes, hit ratio.
Edge rules
Declarative, ordered rules applied at the edge per zone. Set via PATCH /v1/zones/:id with a "rules" array. A matching block/redirect short-circuits; set_header is added to the response.
rule: set_header { "prefix"?: "/path", "action": { "type": "set_header", "name", "value" } }
rule: redirect { "prefix"?: "/old", "action": { "type": "redirect", "status": 301|302|307|308, "location" } }
rule: block { "prefix"?: "/private", "action": { "type": "block" } } โ 403
Storage zones
Object buckets for static files. Upload via presigned PUT, list/delete files, and optionally front a bucket with a CDN pull zone (storage_zone_id on the zone).
/v1/storage-zones write Create a storage zone.
Body { "name" }
/v1/storage-zones read List storage zones.
/v1/storage-zones/:id read Detail incl. bytes_used + file_count.
/v1/storage-zones/:id write Delete the zone and its files.
/v1/storage-zones/:id/upload-url write Presigned PUT for a file path.
Body { "path", "content_type"? }
Returns { url, path }
/v1/storage-zones/:id/files read List files (presigned GET URLs).
/v1/storage-zones/:id/files?path=โฆ write Delete a file by path.
Edge functions
Deploy JavaScript/TypeScript that runs at the edge in a V8 isolate (Deno.serve). Invoke at /__fn/<id> on the CDN host. Deploys propagate in seconds.
/v1/functions write Create + deploy a function.
Body { "name", "code" }
Returns FunctionView
/v1/functions read List functions.
/v1/functions/:id read Get a function (incl. code).
/v1/functions/:id write Update code / name / active. Re-deploys.
Body { "name"?, "code"?, "active"? }
/v1/functions/:id write Delete + undeploy.
/__fn/:id public Invoke the function (any method/path/body passed through).
Webhooks
Subscribe to events. Deliveries are HMAC-signed (X-Signature) with the per-webhook secret (shown once) and retried with backoff. Events: video.asset.ready, video.asset.errored, video.asset.processing, video.asset.created, video.asset.thumbnail.ready, video.asset.track.ready, transcript.ready.
/v1/webhooks write Create a subscription.
Body { "url", "events": ["video.asset.ready"] }
Returns { id, url, events, secret }
/v1/webhooks read List subscriptions.
/v1/webhooks/:id/deliveries read Recent delivery attempts + statuses.
Analytics & usage
Account-wide rollups for dashboards and billing.
/v1/analytics read Storage, video count, total views, by-status, per-day, top videos.
/v1/usage read Current storage_bytes + video_count.
Team & audit
Manage teammates and review the audit trail. Requires the admin scope.
/v1/users admin Add a teammate.
Body { "username", "password", "email"?, "full_name"?, "scopes": [] }
/v1/users admin List teammates.
/v1/users/:id admin Update scopes or disable.
Body { "scopes"?, "disabled"? }
/v1/users/:id admin Remove a teammate.
/v1/users/:id/reset-password admin Set a teammate password.
Body { "new_password" }
/v1/audit admin Audit log (?limit). Every mutation is recorded.
End-to-end: upload & play
# auth
TOKEN=$(curl -s -X POST https://api.ollanode.com/v1/auth/login \
-H 'content-type: application/json' \
-d '{"username":"you","password":"โขโขโขโข"}' | jq -r .token)
# 1) create a video
VID=$(curl -s -X POST https://api.ollanode.com/v1/videos \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"title":"launch.mp4","playback_policy":"signed"}' | jq -r .id)
# 2) presigned upload, then PUT the bytes
URL=$(curl -s -X POST https://api.ollanode.com/v1/videos/$VID/upload-url \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"content_type":"video/mp4"}' | jq -r .url)
curl -X PUT "$URL" -H 'content-type: video/mp4' --data-binary @launch.mp4
# 3) start processing
curl -s -X POST https://api.ollanode.com/v1/videos/$VID/upload-complete -H "authorization: Bearer $TOKEN"
# 4) poll until ready
curl -s https://api.ollanode.com/v1/videos/$VID/status -H "authorization: Bearer $TOKEN"
# 5) get a playback URL (signed)
curl -s https://api.ollanode.com/v1/videos/$VID/playback -H "authorization: Bearer $TOKEN"
# โ { "master_url": "โฆm3u8", "token": "โฆ", "subtitles": [...] }