Video infrastructure for teams whose product isn’t video.

Acme takes a source file, encodes it into an adaptive ladder, stores it, and serves it over HLS from a network of delivery nodes. Your application holds one identifier and a player. Everything between the upload and the viewer is ours to run.

Closed beta · teams are onboarded one at a time

The part nobody wants to own.

Putting video in a product looks like one feature and turns into four systems. An encoder that has to survive whatever came out of someone’s phone. Storage that grows faster than the rest of your data and never shrinks. A delivery layer that decides whether a viewer on a train sees a picture or a spinner. A player that behaves differently in every browser, and differently again on the browser your customer is actually using.

Any competent team can build all four. The question is whether they should be the ones woken up when the fourth one fails on a Sunday.

Five stages, one API surface.

A file arrives, gets validated, encoded into several renditions, stored, and served in segments to a player that picks the one it can sustain. You interact with the first stage and the last one.

Ours to runYour appsource fileIngestvalidateEncodebuild ladderStoremaster + renditionsDeliversegments, cachedPlayyour player Ours to runYour appsource fileIngestvalidateEncodebuild ladderStoremaster + renditionsDeliversegments, cachedPlayyour player

How it works

Three calls and a webhook.

Step 1

Create the asset.

Point Acme at a file you can reach, or ask for a direct upload URL. The response comes back before any encoding starts — the asset exists immediately, but it isn’t playable yet.

Request and response

POST /v1/assets

{
  "source_url": "https://files.example.com/lecture-04.mp4",
  "playback_policy": "signed"
}

201 Created

{
  "id": "as_7Kp2wQ",
  "state": "queued",
  "playback_ids": []
}

Step 2

Wait to be told.

When the asset becomes playable, a webhook says so. When it can’t be encoded, another one says why, in a form you can show your own user. Nothing in your application polls for status.

Webhook delivered to you

POST https://your-app.example.com/hooks/acme

{
  "type": "asset.ready",
  "asset_id": "as_7Kp2wQ",
  "playback_id": "pb_9Fd41C",
  "duration_s": 14412.6,
  "renditions": ["720p", "540p", "360p"]
}

Step 3

Play it.

A playback ID resolves to an HLS manifest. Use the player we ship, or your own — the manifest doesn’t care.

Manifest request

GET /v1/playback/pb_9Fd41C.m3u8?token=eyJhbGciOi…

200 OK

#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=2600000,RESOLUTION=1280x720
720p/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=960x540
540p/index.m3u8

Principles, and what they cost us.

Failure is a state, not an exception.

Every asset that cannot be encoded ends in a terminal state with a machine-readable reason and a sentence you can put in your own interface. Sources fail for boring reasons — a container that lied about its contents, a recording with no audio track, a download that stopped halfway. You get the reason, not silence.

Quality degrades before playback does.

When the network under a viewer gets worse, the player drops to a lower rendition. When a delivery node goes away, the next one serves the same segments. Watching something slightly softer is a much smaller failure than watching a spinner, and the system is built around that order of preference.

The master file stays yours.

You can download the original at any time, and you can delete it and keep only the renditions if storage matters more than re-encoding later. Nothing about the design assumes you’ll stay.

We don’t publish numbers you can’t verify.

There’s no uptime figure on this site. Anyone can print one. Instead there’s a page describing what happens when each part of the system fails, which is the thing you’d actually have to live with.

Where this ends up.

Four kinds of product that carry video without selling it. Each one breaks in its own place first.

Learning

Learning platforms

Breaks first: a ladder tuned for short video, applied to four-hour recordings.

Clinical

Telemedicine

Breaks first: playback links that outlive the consultation they were issued for.

B2B SaaS

Products that record

Breaks first: storage that grows with every session and is almost never revisited.

Media

Media and sports

Breaks first: delivery that meets its whole audience inside the same ten minutes.

“We already had an encoder that worked. What we didn’t have was anyone to page at two in the morning when it stopped working.”

Engineering lead, B2B analytics platform

Access is granted per team.

There’s no signup form and no free tier. Every team on Acme was set up with an engineer from here in the conversation, which limits how many we take at once. If your product needs video and you’d rather not run the pipeline, tell us what you’re building.

Platform

From a file you didn’t choose to a stream that plays.

Your users upload whatever their device produced: a 4K screen recording with a silent audio track, a portrait clip shot on a phone, a decade-old export from an editor nobody supports anymore. The job is to turn that into something that plays on a poor connection in a browser you never tested. This page is what happens in between.

Ours to runwebhook on every state changeYour appsource fileIngestvalidateEncodeStoreDeliverPlayyour player3–6 renditionsmasterrenditionsshieldnodes Ours to runwebhookYour appsource fileIngestvalidate the sourceEncode3–6 renditionsStoremaster + renditionsDelivershield + nodesPlayyour player
The five stages, with the parts that only matter once you look closely: the ladder built at encode, the split between master and renditions at store, the shield in front of storage at delivery, and the webhook that comes back to you.

Ingest: accepting a file you can’t trust.

There are two ways in. Give Acme a URL it can reach and it pulls the file itself, retrying transient failures on its own. Or request a direct upload URL and send bytes to it, resumably, without the file passing through your servers.

Before anything is encoded, the source is inspected: container, video and audio streams, duration, frame rate, colour information. This is where most bad inputs are caught — a file with a video extension and no video stream, a truncated upload, a codec we can’t decode. Catching it here means the asset fails in seconds with a specific reason, instead of failing expensively in the middle of encoding or, worse, producing a technically valid asset that plays as a black screen.

Encode: the ladder is derived, not assumed.

A rendition ladder is the set of qualities a viewer can switch between. Most of the cost and most of the playback experience is decided here.

Acme reads the source and builds a ladder that fits it. A 240-minute lecture recorded at 720p and a two-minute highlight shot at 4K get different ladders, because they have different useful qualities and different viewers.

Highlight clip

2 minutes · 3840×2160 · camera

  • 2160p
  • 1440p
  • 1080p
  • 720p
  • 480p
  • 360p

Recorded lecture

240 minutes · 1280×720 · screen

  • 1080p
  • 720p
  • 540p
  • 360p

Phone clip

40 seconds · 1080×1920 · portrait

  • 1080p
  • 720p
  • 480p
  • 360p
Three sources, three ladders. The 720p lecture produces no 1080p rendition: the dashed rung is the one that isn’t built.

Two rules hold in every case. We don’t upscale: if the source is 720p, no 1080p rendition is produced, because it would cost you delivery bandwidth and give the viewer nothing that wasn’t already there. And screen recordings are treated differently from camera footage: a slide with 10pt text falls apart under settings that look perfectly fine on a face, so encoding decisions account for what the frame contains.

Audio is normalised and encoded once, separately from video, so switching quality mid-playback doesn’t interrupt sound. Thumbnails and a scrubbing preview strip are generated in the same pass — they’re needed by almost every interface, and asking you to make a second pipeline for them would be strange.

Store: two things worth keeping.

The master is the file as you gave it to us. The renditions are what viewers actually receive. They’re stored separately and priced separately, because they have different lifetimes.

Keep the master and you can re-encode later — a new rendition for a device that didn’t exist when the video was uploaded, a different ladder when your audience changes. Drop it and you keep playback while paying for less storage. Which of those is right depends on your catalogue, and it’s your decision to make per asset, not a platform default you have to live with.

Deliver: segments, close to the viewer.

HLS splits a rendition into short segments and describes them in a manifest. The player reads the manifest, requests segments one at a time, and can change its mind about quality between any two of them.

Segments are served from delivery nodes. A node that doesn’t have a requested segment fetches it once from a shielding layer in front of storage, then keeps it — so the first viewer of a video in a region pays a small latency cost and everyone after them doesn’t. Storage is never hit by viewer traffic directly.

Playerthe viewerDelivery nodekeeps segmentsrequestShieldone fetch per misscache missStoragemaster + renditionsshield missviewer traffic never reaches here Playerthe viewerDelivery nodekeeps segmentsrequestShieldone fetch per misscache missStoragemaster + renditionsshield missviewers never reach these two
One fetch per miss, then the node answers on its own. The shield exists so that a cold region costs storage one request, not thousands.

Manifests and segments go out over TLS. Playback can be open, or restricted to signed URLs that expire.

Play: the client chooses, the ladder decides.

Adaptive bitrate is a negotiation, and the player is the only participant with real information. It measures how fast segments are arriving and how full its buffer is, then picks the highest rendition it can sustain. When a train enters a tunnel, it steps down. When the connection recovers, it steps back up.

bandwidth available to one viewerrendition the player picks1080p720p360pthe player reacts after it measurestime bandwidth availablerendition the player picks1080p720p360ptimethe player reacts after it measures
The step down follows the drop rather than predicting it, and the step back up waits until the connection has held. Both delays are deliberate: switching on every fluctuation is worse than switching late.

That means playback quality is decided by two things: the network the viewer has, and the ladder we built. We can’t affect the first one, which is exactly why the second one gets the attention it does.

Acme ships a player as a web component with the states you’d otherwise implement yourself — loading, buffering, recoverable error, unrecoverable error, expired link. You’re not required to use it. The manifest is standard, and any player that speaks HLS will work.

An asset is a small state machine.

created -> uploading -> queued -> encoding -> ready, with errored reachable from anywhere before ready and deleted reachable from anywhere at all. Every transition emits a webhook. The states are deliberately few: if you’re writing a switch statement against them, it should fit on one screen and it shouldn’t need updating when we ship something.

every transition emits a webhook · double border = terminal statecreateduploadingupload.startedqueuedupload.doneencodingencode.startedreadyasset.readyerroredasset.errored · before readydeletedasset.deleted · any state every transition emits a webhookdouble border = terminal statecreateduploadingupload.startedqueuedupload.doneencodingencode.startedreadyasset.readyerroreddeletedbefore readyfrom anywhere
Asset states, what each one means, what you can do in it, and whether it is terminal
State What it means What you can do Terminal
created The asset exists and has an identifier. No bytes have arrived. Attach your own metadata, request an upload URL. no
uploading Bytes are arriving, either from your upload or from our pull. Cancel. Watch progress on the upload itself. no
queued The source is complete and inspected, waiting for a worker. Cancel. no
encoding Renditions are being produced. Thumbnails appear before the last rendition does. Cancel. no
ready At least one rendition plays. The rest arrive without changing this state. Play, sign links, download the master, delete either part. no
errored The source could not be encoded. Carries a machine-readable reason. Read the reason, show it to your user, upload a different source. yes
deleted Master, renditions and playback IDs are gone. Segments are purged from nodes. Nothing. The identifier stays resolvable so your own records still make sense. yes

What Acme is not.

Not live.

The pipeline described here starts with a complete file. Live ingest is a different system with different failure modes, and calling it a feature of this one would be dishonest. It isn’t part of the beta.

Not an editor.

We produce thumbnails, previews and renditions. Trimming, captions burned into the frame, overlays and edits belong to your product, not to the delivery layer.

Not a moderation service.

We don’t inspect what’s in your video. If your product needs to decide whether content is allowed, that decision is yours and it happens before or after us.

Not a media rights platform.

Signed, expiring playback links protect against casual sharing. Studio-grade content protection is a different category of product with different obligations, and we don’t claim it.

Everything above is what runs before your first line of code.

Access opens per team.

Developers

Read this before the reference.

The full reference opens when your account does. This page is the part worth knowing beforehand: the objects, the lifecycle, the failure modes, and the shape of the code you’d write. Everything below is stable — it’s what the beta teams are building against.

Six objects, and only two of them you’ll think about daily.

Asset

One piece of source content and everything derived from it. This is the object you create, watch, and delete.

Rendition

One quality level produced from an asset. You rarely address these directly; the manifest does.

Playback ID

What you store next to your own records and hand to a player. Separate from the asset ID on purpose: you can revoke a playback ID without destroying the asset behind it.

Upload

A short-lived destination for direct uploads, with its own expiry.

Signing key

Used to produce expiring playback tokens. Created and rotated by you.

Webhook endpoint

Where lifecycle events go, with a secret used to verify they came from us.

The lifecycle, in the fields you’ll actually read.

Three exchanges cover an integration: you create an asset, we tell you it’s playable, and we tell you when it isn’t going to be.

Create the asset.

The response returns before encoding starts. playback_ids is empty until a rendition exists, so a handler that waits for it will wait correctly.

Request and response

POST /v1/assets

{
  "source_url": "https://files.example.com/lecture-04.mp4",
  "playback_policy": "signed",
  "keep_master": true,
  "passthrough": "course-114/lesson-4"
}

201 Created

{
  "id": "as_7Kp2wQ",
  "state": "queued",
  "playback_ids": [],
  "passthrough": "course-114/lesson-4",
  "created_at": "2026-04-08T09:12:44Z"
}

It becomes playable.

The event carries the ladder that was chosen, so you can show a quality selector without asking us a second question.

Webhook delivered to you

POST https://your-app.example.com/hooks/acme

{
  "type": "asset.ready",
  "asset_id": "as_7Kp2wQ",
  "state": "ready",
  "playback_id": "pb_9Fd41C",
  "duration_s": 14412.6,
  "renditions": [
    { "height": 720, "bitrate_kbps": 2600 },
    { "height": 540, "bitrate_kbps": 1400 },
    { "height": 360, "bitrate_kbps":  700 }
  ]
}

Or it doesn’t.

The reason has three parts: a stable code to branch on, a sentence you can show your own user, and whether trying the same file again could help.

Webhook delivered to you

POST https://your-app.example.com/hooks/acme

{
  "type": "asset.errored",
  "asset_id": "as_3Rm8xB",
  "state": "errored",
  "error": {
    "code": "no_video_track",
    "message": "The container holds one audio stream and no video stream.",
    "retryable": false
  }
}
Asset states expressed as the fields of an asset response
state playback_ids duration_s error
createdemptynullnull
uploadingemptynullnull
queuedemptyread from the sourcenull
encodingpresentsetnull
readypresentsetnull
erroredemptyset if we got that farcode, message, retryable
deletedemptykeptnull

A playback ID appears while encoding is still running: the first rendition to finish is servable, and the rest arrive without changing the state.

Webhooks, and what to expect from them.

Events are signed with your endpoint secret; verify the signature before trusting the body. Delivery is retried with backoff if your endpoint doesn’t respond with success, so your handler needs to be idempotent — the same event can arrive twice, and events for the same asset can arrive out of order under retry. Every event carries the asset’s current state, so a handler that reads state from the payload rather than inferring it from event order will be correct in every case.

If your endpoint is unreachable for long enough, events stop being retried and are kept for you to fetch when you come back. Nothing is silently dropped.

When encoding fails.

Roughly one upload in a few hundred fails, and almost always for the same handful of reasons. Each one returns a stable code, a human-readable message, and a flag telling you whether retrying the same file could possibly help.

Encoding error codes, what each means, what to show a user, and whether a retry can help
Code What happened What to show your user Retry
unsupported_codec The streams are readable but encoded with something we can’t decode. “This file’s format isn’t supported. An MP4 export will work.” no
no_video_track The container holds audio only, often a screen recorder that captured the wrong source. “There’s no video in this file.” no
corrupt_container The index is damaged or the upload stopped partway. “This file arrived incomplete. Uploading it again usually fixes it.” yes
source_unreachable The URL you gave us didn’t answer, or answered with something that wasn’t the file. Nothing — this one is between your systems and ours. yes
source_too_long The duration is past the limit set on your account. “This recording is longer than we can process.” no
duration_zero The file is structurally valid and contains no frames. “This recording is empty.” no

Sandbox and production are separate accounts, not a flag.

Sandbox assets are encoded through the same pipeline with a shorter retention and a watermark, so integration testing costs almost nothing and can’t accidentally serve a real viewer. Keys are scoped by capability — a key that can create assets doesn’t have to be a key that can delete them — and rotating one doesn’t interrupt playback, because playback tokens are signed separately.

What you can see without adding logging of your own.

Per asset: the source properties we read, the ladder we chose, how long encoding took, and the exact reason if it failed. Per endpoint: every webhook attempt, its response code, and a way to replay it. Per playback: startup time, stalls, and rendition switches, aggregated — enough to tell “our video is broken” from “that viewer’s network was”.

as_7Kp2wQ

ready

source

1280×720 · 30 fps · h264 · aac · 4:00:12

detected as

screen capture, low motion

encode time

18 min 04 s

ladder chosen

720p
540p
360p

No 1080p rendition: the source is 720p.

hooks/acme

last 4 attempts

09:12:47

asset.created

200

09:31:02

asset.ready

502

09:31:12

asset.ready · retry 1

200

10:04:55

asset.deleted

200

The failed attempt was retried ten seconds later and accepted. Any attempt can be replayed by hand from here.

as_3Rm8xB

errored

code

no_video_track

source

aac · 00:41:19 · no video stream

reason

The container holds one audio stream and nothing else. This is what a screen recorder produces when it captures the wrong source.

retrying the same file will not help

These are screens from the account console, which opens with access. They’re here because the failure case is the one worth showing.

What opens with your account.

The full API reference, client libraries, the player’s configuration surface, webhook event schemas, migration notes for anyone moving an existing catalogue, and the runbook we use ourselves for triaging playback complaints. It isn’t public because it changes weekly during the beta and because we’d rather answer questions from teams we’re talking to than publish a document that ages in the open.

The reference, the libraries and the channel open together, per team.

That starts here.

Reliability

What happens when something breaks.

There’s no uptime percentage on this page. Anyone can print one, nobody publishes the arithmetic behind it, and it tells you nothing about the failure you’ll actually meet — which will be partial, regional, and specific. What follows is how the system behaves when parts of it stop working. That’s the part you can hold us to, and the part we’d want to read first if we were buying this.

The control plane is not on the playback path.

If our API is degraded, you can’t create new assets and you won’t get webhooks. Playback of everything that already exists continues, because manifests and segments are served by the delivery layer and never require the control plane to answer a question.

Control planePlayback pathYour appAPIEncodeViewerNodeShieldStorageplayback never asks the control plane a questionwritten once, at encode time Control planeYour appAPIEncodeplayback never asks the line aboveViewerNodeShieldStoragePlayback path
One arrow crosses between the two lines, and it points downward: encoding writes renditions into storage. Nothing on the playback path reads back up.

This separation is the single most important thing on this page. It means our worst days affect your ability to add new video, not your viewers’ ability to watch what’s already there.

What each failure actually costs you.

Seven things can stop working independently. For each one: what a viewer notices, what your application notices, and how long it lasts.

Failure domains, what a viewer sees, what your application sees, and how long each lasts
What failed The viewer sees Your application sees How long
A delivery node Nothing. The next node serves the same segments. Nothing. Seconds, and only for requests that were in flight.
A whole delivery region One rebuffer, then playback continues from further away. Nothing. Until routing settles. Startup time stays higher in that region while it lasts.
An encoding worker Nothing. Existing video is untouched. One asset stays in encoding longer than usual. One retry cycle. The job moves to another worker.
The encoding queue backs up Nothing. New assets take longer to reach ready. Until the backlog clears. If the cause is ours, you hear it from us first.
The shield or origin Nothing for anything already cached. Cold segments fail to load. Nothing. Popular video is unaffected throughout, because it isn’t being fetched.
The control plane Nothing at all. Creating, listing and deleting fail. Webhooks pause. Playback is unaffected for the entire duration, however long that is.
Webhook delivery to you Nothing. Events arrive late, and possibly twice. Until your endpoint answers. Then the backlog is delivered, not dropped.

Playback degrades before it stops.

The order of sacrifice is fixed and deliberate. First the player drops to a lower rendition. Then it retries segments from another node. Then it holds the last playable position rather than resetting. Only after all of that does the viewer see an error, and when they do, the player says whether retrying is worth it.

NormallyViewerShieldNode ANode BThat node stops answeringViewerShieldNode ANode Bthe viewer keeps watching, and the segments are the same ones NormallyViewerShieldNode ANode BThat node stops answeringViewerShieldNode ANode Bplayback continues on the next node
A node leaving is the ordinary case, not the incident. The segments it was serving exist on the shield behind it, so the next node answers with the same bytes.

The same principle applies upstream: an asset whose highest rendition fails to encode becomes playable at the qualities that succeeded, rather than failing whole.

Encoding is retried, not lost.

A worker that dies mid-encode doesn’t take the job with it. The asset returns to the queue and is picked up elsewhere; retries are bounded, and when they’re exhausted the asset ends in a terminal state with a reason. What never happens is an asset sitting in encoding forever — every job has a deadline, and hitting it is itself a reportable outcome.

Retried work isn’t billed twice. You pay for the source you submitted, not for our attempts at it.

Load you didn’t warn us about.

Delivery absorbs spikes without notice: that’s what the node layer is for, and a popular video is the easy case, since every viewer after the first is served from cache.

Encoding is the part with a real queue. A sudden bulk import competes with everyone else’s work, so during the beta capacity is allocated per team and large migrations are scheduled rather than discovered. If your product has a predictable weekly peak, tell us in the first conversation and it stops being a surprise for both sides.

When we’re the problem.

Teams in the beta get a direct channel and a status feed that’s part of the account, not a public page — the audience for it is the teams running on us, and they’re the ones who get notified. During an incident we say what is affected, what isn’t, and what we’re doing, updated on a schedule rather than when there’s good news. Afterwards, a written account of what happened and what changed goes to everyone affected, whether or not they noticed.

What you can measure yourself.

Playback metrics are exported, not only displayed: startup time, stall rate, rendition distribution, and error codes, broken down enough to separate our problem from a bad network. We’d rather you had your own numbers than took ours. Contractual commitments are agreed per team, in writing, when you join — and they describe the same behaviour this page does.

If this is the level of detail you expect from an infrastructure vendor, we should talk.

Data and security

Where your video lives and who can reach it.

Video is often the most sensitive object a product stores. A consultation, an internal incident review, a customer’s own recording of their own work. This page answers what a security reviewer usually asks, in the order they usually ask it. If your questionnaire has more, send it with your access request — it’s a normal part of onboarding, not an obstacle to it.

What we store, and what we don’t do with it.

We store the source you gave us, the renditions derived from it, and the technical metadata needed to serve them: durations, resolutions, timings, request logs. We don’t inspect the content of your video, index it, generate transcripts of it unless you ask for that as a feature, use it to train anything, or make it reachable by anyone your keys haven’t authorised. There is no product on our side that improves by looking inside your files.

Who can play an asset.

An asset can be openly playable, or require a signed token. A token is produced by you, from a key only you hold, and carries an expiry — and optionally a restriction to a viewer, a session, or an origin. Acme validates it at the delivery layer, which means an expired or altered link fails at the node, before any bytes leave.

https://cdn.example.net/v1/playback/ a delivery node, never your origin pb_9Fd41C which asset — revocable on its own /index.m3u8 the manifest ?exp=1775644800 until when &scope=session:8f21 for whom — optional &sig=8a3f2e…c701 signs everything before it
A signed playback link, in parts. Change any character before the signature and the signature stops matching.
PlayerDelivery nodesignature, expiry, scoperequest with tokensegmentsrefused, no byteschecked at the node, before anything leaves it Playerrequest with tokenDelivery nodesignature, expiry, scopesegmentsrefusedchecked before anything leaves
The check happens at the delivery node. A link that expired an hour ago costs one rejected request, not one served segment.

Short expiries are the ordinary case rather than the strict one. A link that lives for minutes and is issued per view is much less interesting to copy, and it turns “someone shared the URL” from a breach into a nuisance.

Revoking a playback ID stops future manifest requests immediately. Segments already cached by a viewer’s own player remain in that player until they’re evicted — no delivery system can reach into a browser’s cache, and any vendor telling you otherwise is describing something they can’t do.

Encryption and isolation.

Traffic is encrypted in transit and stored objects are encrypted at rest, with keys we manage and rotate. The mechanics are described to your reviewer in full rather than summarised into a sentence here, because a sentence about key management is worth very little to the person whose job is to check it.

Accounts are isolated from each other, and a sandbox account is a different account rather than a flag on yours. Playback IDs are long random identifiers rather than sequential ones, so there is no neighbouring asset to arrive at by adding one — and enumeration attempts are rate-limited at the delivery layer regardless.

Where processing and storage happen.

The region for processing and storage is chosen per account. This matters if you have requirements about where data sits, and it’s the kind of thing that’s expensive to change after a catalogue exists — so it belongs in the first conversation, not the second year. Delivery stays global either way: segments are cached close to viewers wherever they are, and that caching is of already-encrypted, already-derived output rather than of your master.

Deletion is a request that completes, not a flag that hides.

Deleting an asset removes the master and the renditions, invalidates its playback IDs, and purges the segments from delivery nodes. Backups age out on a stated schedule, and we tell you what that schedule is rather than describing it as “a reasonable period”.

You can set a retention rule per account so that assets are removed on their own after a period you choose — which is usually what teams with regulatory obligations actually need, instead of remembering to call delete.

Who inside our team can reach your content.

Nobody, in the ordinary case. Support can see an asset’s technical record — its state, its ladder, its error — without being able to play it, because those are different permissions and reading the record is what answers almost every question.

Investigating a specific failure sometimes requires more. When it does, the access is requested against a named asset, granted for a limited period, and written to a log you can ask to see. We would rather tell you that this path exists than describe an access model that nobody could operate.

What we can send your reviewer.

A data processing agreement, answers to your questionnaire in your own format, the categories of subprocessor we rely on and the current list, the retention and deletion policy, and the incident notification procedure with the timelines written into it.

What you won’t find here is a row of certification badges. During a closed beta, claiming an audit we haven’t completed would be the one thing on this page you couldn’t verify — so the honest version is this: ask what you need, and you’ll get either the document or a straight answer about when it exists.

Reporting a vulnerability.

Write to us and a person answers — not a form, and not a legal notice. Good-faith research is welcome and we won’t pursue anyone for it.

One request: don’t test against another team’s assets. The sandbox exists for exactly this, and if you don’t have one, ask and we’ll open one for the purpose.

Your reviewer’s questionnaire is welcome.

Send it with the access request.

Pricing

How this is priced, before what it costs.

Commercial terms are agreed per team during the beta, so there’s no price list here. What is here: exactly which units we count, which ones we don’t, and what moves them — enough to model your own bill and check ours against it later.

Your appIngestEncodeStoreDeliverPlayEncodingper minute of sourceStorageper GB per monthDeliveryper GB servedingest, thumbnails, webhooks and API calls are not counted Your appIngestEncodeEncodingper minute of sourceStoreStorageper GB per monthDeliverDeliveryper GB servedPlayingest and webhooks are not counted
The same pipeline as everywhere else on this site, with the three billed stages marked. Nothing is counted at the ends.

Three units, and each one is a decision you control.

Encoding — per minute of source.

Counted once per minute of the file you submitted, regardless of how many renditions come out of it. A wider ladder costs you delivery, not encoding. Failed and retried encodes aren’t counted.

Storage — per gigabyte per month.

Master and renditions counted separately, because you can keep one without the other. Deleting the master after a video has settled is the single easiest reduction available to most catalogues.

Delivery — per gigabyte served.

The unit that grows with your success rather than your library, and the one that surprises people. What’s served depends on how much your audience actually watches and at which quality their networks allow — which is why the ladder is a cost decision, not only a quality one.

What isn’t counted.

API requests. Webhook deliveries and their retries. Failed encodes. Encoding retries after our own failures. Thumbnails and preview strips. Downloading your own master. Sandbox usage within the limits of the environment. None of these are complicated enough to be worth metering, and metering them would make your bill harder to predict for a rounding error.

What moves the bill.

Ladder width.

Fewer renditions mean less delivery and a coarser experience on bad networks. Capping the top rendition is usually the cheaper decision than removing the bottom one.

Master retention.

Keep it and you can re-encode later. Drop it and re-encoding requires a new upload.

How much is actually watched.

Delivery follows watch-through, not catalogue size. A library nobody finishes costs almost nothing to deliver and quite a lot to store.

Your audience’s networks.

An audience on good connections pulls higher renditions and costs more per viewed minute. This one you don’t control, but it explains variance between months.

What to bring to the first conversation.

Not a demo, a worksheet. Four numbers get you within a reasonable range:

  1. Hours of source uploaded per month.
  2. Average length of a source file.
  3. How much of a typical video your users actually watch.
  4. The size of the catalogue you’d be storing on day one.

If you’re migrating an existing library, the fifth number is how big it is today and how fast it grew last year.

Terms during the beta.

Beta teams get terms that reflect what the beta is: usage-based pricing agreed in writing, no minimum commitment, no long contract, and the ability to leave with your masters. When pricing becomes public, the model on this page is what gets numbers attached to it — the units won’t change underneath anyone.

Bring the numbers from the worksheet and the first conversation can be specific.

Where it fits

Four products with the same pipeline and different weak points.

The stages underneath don’t change. What changes is which one you can’t afford to get wrong — and that turns out to depend far more on your product than on your scale.

Learning platforms.

the load

long sources, a catalogue that only grows, viewers on every device and network

what matters

resuming where they left off, legible text on slides, the cost of a catalogue watched unevenly

breaks first

the storage bill — video accumulates, and mostly the recent part is watched

This is the case the per-asset master decision exists for. Keeping every original for a catalogue where half the material is never opened again is the most common way a learning platform’s bill stops matching its usage. Dropping the master keeps playback and stops paying for the part nobody re-encodes.

It also drives how the ladder is built: a recorded lecture is a screen capture with 10pt text in it, and encoding decisions that look fine on a face fall apart on a slide.

“Half our catalogue is watched in the first two weeks and then almost never. We needed storage decisions to be per-video, not per-account.”

CTO, professional education platform

Telemedicine and clinical records.

the load

modest volume, high sensitivity, firm requirements about location and retention

what matters

the processing and storage region, short-lived links, deletion you can demonstrate

breaks first

not the engineering — the review. An integration stops at a question the vendor can’t answer in writing

Everything on the data and security page exists because of this shape of customer: the region chosen per account, tokens that expire in minutes rather than days, retention rules that remove assets without anyone remembering to call delete, and an honest sentence about what a delivery network can and cannot purge from a viewer’s own browser.

The part that isn’t technical matters as much. A reviewer’s questionnaire arriving before the first call is a good sign, not an obstacle.

“The engineering integration took a week. Getting an answer about where the files physically sit took three months with the previous vendor.”

Head of engineering, clinical software company

B2B SaaS with recordings.

the load

tied to the working calendar: silence overnight, hundreds of meeting recordings inside one hour

what matters

how the queue behaves at the peak, and text quality at middling bitrates

breaks first

time to ready during the peak — the user waits for their own recording right after the meeting

Encoding is the stage with a real queue, and this is the product shape that finds its edge. A load that arrives as a comb rather than a curve is a scheduling problem before it is a capacity one, which is why beta capacity is allocated per team and a predictable weekly peak is something to say out loud in the first conversation.

Sources here are almost always screen capture, so the encode-side rule about screen recordings is doing most of the work you’d notice.

“Every recording finishes at the top of the hour. Our load is not a curve, it’s a comb.”

Founder, revenue intelligence product

Media and sports apps.

the load

short clips, sharp spikes of attention, a viewer who leaves faster than they wait

what matters

time to first frame, and delivery behaviour when everyone watches the same thing at once

breaks first

the start of playback, not its continuation

A popular clip is the easy case for delivery: the first viewer in a region pays a small latency cost and every viewer after them is served from the node. The hard case is the first few seconds — a ladder whose bottom rung is genuinely usable matters more here than a wide top, because the player’s first choice is made with almost no information.

“Nobody complains about quality. They don’t press play a second time if the first one took too long.”

Product lead, sports media app

Where Acme is a poor fit right now.

Live.

Not part of the beta, and not a small addition to what’s here.

Consumer-scale user-generated video.

Millions of uploads a day with moderation in the loop is a different product with different economics. We’d rather say so than take the workload and run it badly.

Anything that needs editing as a service.

Cutting, captions rendered into the frame, compositing — that’s your product’s job, and if it’s the main thing you need, we’re the wrong layer.

Premium media with rights obligations.

If a contract requires a specific content protection scheme, we don’t meet it today.

If your case is close to one of these, say which one in the request.

Company

A company that only works if the layer underneath is uneventful.

Acme exists because video became a default expectation in products that have nothing to do with media, while the infrastructure for it stayed something you either assembled yourself or bought as part of a platform built for someone else’s business. This page is what we think about that, in enough detail that you can disagree with it.

Why we’re building this.

Every few years a capability stops being a project and becomes a line item. Payments did it. Search did it. Video is doing it now: a support tool records sessions, a training product ships a course, a clinical system keeps a consultation — and not one of those teams set out to operate an encoder.

What’s available to them is usually one of two things. A set of primitives — object storage, a transcoding service, a delivery network — that someone has to wire together and then own for as long as the product lives. Or a platform designed for media companies, priced and shaped around a business whose product is the video itself.

Most products sit between those two, and that gap is where we work. It’s not a glamorous position. Infrastructure is noticed on its worst day and invisible on every other one, and we’d like to keep the ratio that way round.

How we work.

We publish behaviour, not numbers.

There’s no uptime figure on this site, no customer count, and no wall of logos. Those are the easiest things to print and the hardest to check, and printing them would make everything else here less believable. What we publish instead is how the system behaves when it fails, which is harder to write and impossible to fake.

We’d rather refuse a workload than run it badly.

There’s a list of cases we turn away, and it’s on the site rather than in an internal document. Taking on something we can’t run well costs the team that trusted us and every team queued behind them.

Your data leaves as easily as it arrived.

Masters are downloadable, playback is standard HLS, and nothing in the design makes migrating away harder than migrating in. A product that retains customers by making departure expensive stops having a reason to improve.

Breaking changes are dated before they happen.

The API still moves during the beta. When it moves, teams hear a date in advance and get a version to stay on — not a changelog entry after their integration broke.

Support is staffed by people who can read the pipeline.

A question about why an asset failed reaches someone who can look at why it failed. Putting tiers between customers and engineers is how a vendor stops finding out what’s wrong with its own product.

What we’re building next.

More control over the ladder for teams whose sources are unusual — long-form screen capture and high-motion footage pull in opposite directions, and today we choose for you more often than we’d like.

Finer placement of storage and processing, because “which region” turns out to be a per-asset question in more products than we expected.

Playback analytics that answer product questions rather than infrastructure ones: not only how playback performed, but whether people watched.

And live, eventually, as its own system rather than a checkbox on this one — not before the file pipeline is something we’d stake the company on.

There are no dates on this list, and there won’t be until something is close enough that a date would be a commitment rather than a guess.

What we ask from beta teams.

Beta teams get direct access to the people building this, and a real say in what gets built next. In exchange we ask for two things: tell us when something is worse than what you had before, and let us look at real failures in your account when they happen.

That’s the whole exchange, and it’s the reason the beta is small. It doesn’t scale, and at this stage it isn’t supposed to.

There’s one way in.

The access request is it. No sales line, no separate partnerships address, no chat widget waiting to qualify you. If you want to talk about something other than access, use the same form and say so — it reaches the same people.

If you’d argue with any of this, that’s a conversation worth having — same form.

The closed beta

Access is granted, not signed up for.

Every team running on Acme was set up with an engineer from here in the conversation. That’s a hard limit on how many teams we take at once, and it’s deliberate: infrastructure that someone integrates unattended is infrastructure whose failures we hear about late, from a frustrated customer, instead of early, in a shared channel.

Three reasons, and none of them is scarcity.

The pipeline is opinionated, and the opinions are still being tested.

How ladders are derived, what gets retried, what fails fast — these are decisions, and they’re better decisions after they’ve met a few more real catalogues. A team we’ve spoken to knows which of them apply to their case before they build against them.

Encoding capacity is allocated, not infinite.

Taking on a workload nobody has sized is how everyone else’s assets end up in a queue behind it. We’d rather schedule your first bulk import than discover it.

The documentation changes weekly.

Answering questions in a channel is honest at this stage. Publishing a reference that quietly ages in the open is not.

What happens when you’re in.

A technical conversation first.

What you’re building, what your sources look like, what your load does across a week. Not a sales call — a possible outcome is that this isn’t the right time for either side.

A sandbox account.

With the full reference, the client libraries, and no meaningful cost attached to trying things.

An integration session.

With the engineer who’ll be in your channel afterwards. Not a hand-off between two people who’ve never spoken to each other about you.

A direct channel.

Staffed by people who can read the pipeline logs rather than route your question to someone who can.

A review before you serve real viewers.

Your ladder, your retention rules, your token expiries, and what your webhook handler does when the same event arrives twice. Most integration problems we’ve seen live in that last one.

This fits you right now if:

  • Video matters in your product, and your team would otherwise build the pipeline yourselves.

  • Your sources are files, not live streams.

  • You can name roughly how much video goes through this in a month, even if the number is small.

  • Someone on your side can integrate in the next few weeks — a beta account nobody touches helps neither of us.

It doesn’t fit yet if:

You need live. Your product is consumer-scale user-generated video. You need a public price list before a conversation. Or you need a completed compliance review before any technical work — those documents come during onboarding, and onboarding starts with talking.

What happens after you send this.

Someone technical reads it. Not a queue, not a scoring model.

If your case fits what we can run well right now, you get a short set of questions back and a time to talk.

If it doesn’t, we say so, and we say what would change that. We’d rather be a clear no than an open maybe — a company that never says no is a company whose yes doesn’t mean much.

Either way, you get an answer. This is not a mailing list.

The form asks for six things, and one of them is a paragraph.

That paragraph is the part we actually read.

Request access to the closed beta

We reply to this address and nowhere else.

An engineer reads this one. What the video is, where it comes from, and who watches it — detail helps more than polish.

0 of 100 characters minimum

An order of magnitude is enough.

What we won’t do with this.

No newsletter, no sequence of nudges, no call from someone who hasn’t read what you wrote. What you tell us about your product stays with the people evaluating whether we can run it.

Legal

What we do with data.

Two kinds of data pass through Acme: what you tell us when you ask for access, and the video your product sends into the pipeline. They’re handled differently, so they’re described separately.

Everything here is written down properly somewhere else.

This page is the readable version. The agreement your team signs is the binding one, and it arrives with the onboarding pack rather than after it.

Legal

Terms, in the order they matter.

Acme is in closed beta, and every team runs under an agreement signed with them. This page is the readable version of what that agreement says. It isn’t a substitute for it.

Questions about any of this belong in the first conversation.

Onboarding starts with talking, and this is a normal thing to talk about.

404

That address doesn’t resolve.

This site is a handful of sections and one form. The address you followed isn’t one of them — most likely a typo, or a link from a version of the site that has since changed.