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.
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.
Three calls and a webhook.
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.
POST /v1/assets { "source_url": "https://files.example.com/lecture-04.mp4", "playback_policy": "signed" } 201 Created { "id": "as_7Kp2wQ", "state": "queued", "playback_ids": [] }
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.
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"] }
Play it.
A playback ID resolves to an HLS manifest. Use the player we ship, or your own — the manifest doesn’t care.
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 platforms
Breaks first: a ladder tuned for short video, applied to four-hour recordings.
Telemedicine
Breaks first: playback links that outlive the consultation they were issued for.
Products that record
Breaks first: storage that grows with every session and is almost never revisited.
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.
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.
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
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.
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.
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.
| 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.
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.
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.
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.
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 } }
| state | playback_ids | duration_s | error |
|---|---|---|---|
created | empty | null | null |
uploading | empty | null | null |
queued | empty | read from the source | null |
encoding | present | set | null |
ready | present | set | null |
errored | empty | set if we got that far | code, message, retryable |
deleted | empty | kept | null |
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.
| 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
source
1280×720 · 30 fps · h264 · aac · 4:00:12
detected as
screen capture, low motion
encode time
18 min 04 s
ladder chosen
No 1080p rendition: the source is 720p.
hooks/acme
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
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.
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.
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.
| 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.
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.
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
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.
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.
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:
- Hours of source uploaded per month.
- Average length of a source file.
- How much of a typical video your users actually watch.
- 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.
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.
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.
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.
Sent.
Your request is with the people who decide on it. In order:
- Someone technical reads what you wrote. Not a queue, not a scoring model.
- If your case fits what we can run well right now, a short set of questions comes back, with a time to talk.
- If it doesn’t, you get a clear no and the reason — usually something specific that would change it.
You get an answer either way. Nothing else is sent to that address.
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.
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.
What you send with an access request.
The form on the access page collects a work email, a company, a role, a description of what you’re building, a rough volume, a timeline, and optionally how you heard about us.
It goes to the people evaluating whether we can run your workload. It is not added to a mailing list, not enriched from third-party sources, not scored by a model, and not passed to anyone whose job is selling. We reply to the address you gave and to no other.
If you’d rather we didn’t keep it, say so in a reply to our answer and it’s removed. If the conversation doesn’t go anywhere, it’s removed on its own — we don’t keep a file of teams that said no.
Your video, and what we’re bound to.
Your video and everything derived from it stays yours. We hold it to run the pipeline you asked for, on your instruction, and for nothing else.
What we hold: the source file, the renditions built from it, and the technical record needed to serve them — durations, resolutions, encoding decisions, request logs.
What we’re bound not to create: transcripts you didn’t ask for, an index of what’s in your video, training material of any kind, and any copy reachable by someone your keys haven’t authorised. This is an undertaking, not a description of current practice that could quietly change.
Request logs record which segments were served, when, and to which network — the information needed to bill you and to explain a delivery problem. They are not combined with anything that would identify a viewer to us.
Who can reach an asset.
Access is controlled by keys only you hold. We can’t grant anyone access that you didn’t, and we don’t keep a copy of your signing key that would let us.
What we can do is stop serving: revoking a playback ID takes effect on the next request that arrives.
One limit belongs in plain sight rather than in a footnote. A segment already sitting in a viewer’s own browser is beyond the reach of any delivery system, ours included. Revocation stops what comes next; it cannot recall what a player already has.
How a token is formed, what it can be narrowed to, and the point at which it’s checked are described on the data and security page.
Encryption, separation, location.
Traffic is encrypted in transit and stored objects are encrypted at rest. Accounts are separated from one another, and a sandbox is a separate account rather than a setting on your production one.
The region where your video is processed and stored is fixed per account and named in your agreement. Changing it later means moving a catalogue, which is why it is settled before there is one.
The mechanics of each of these are on the data and security page. What’s on this page is what we’re held to.
Removing things.
A delete request runs to completion rather than setting a flag on a row that stays. What it reaches and what it invalidates is listed on the data and security page; the undertaking here is that nothing survives it quietly.
Backups age out on a schedule that is written into your agreement with an actual number in it.
A retention rule set on your account removes assets on their own after a period you choose, which is what obligations of this kind usually require in practice — an automatic rule rather than a person who has to remember.
Closing an account applies the same thing to everything inside it.
Who on our side can reach it.
Nobody, as a matter of routine. Support answers almost every question from the technical record — state, ladder, error — without playing anything.
A specific failure sometimes needs more than the record. When it does, access is requested against a named asset, limited in time, and written to a log you can ask to see. We would rather tell you this path exists than describe a model nobody could operate.
We rely on a small number of subprocessors for compute, storage and network capacity. The current list is part of the onboarding pack, and you are told before it changes.
If something goes wrong.
If data is exposed, we tell the affected teams directly, with what we know at the time, and keep telling them as we learn more. The notification timeline is written into the agreement rather than promised loosely here.
If you have found a weakness rather than suffered one, the reporting route and what we undertake in return are on the data and security page.
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.
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.
Who gets to use it.
Access is granted per team, and the keys belong to that team. Keeping them secret is your side of it: anything done with a valid key is treated as done by you, because from the delivery layer there’s no way to tell otherwise.
Sandbox accounts exist for building against. Production accounts exist for real viewers. Using a sandbox to serve real traffic will work until it doesn’t, and that’s not a limit we’ll be sympathetic about.
Your content stays yours.
You keep every right you had in what you upload. We get exactly the permission needed to run the pipeline: to store the file, derive renditions from it, and serve those renditions to the viewers you authorise. Nothing broader.
You’re responsible for having the right to the video you send, and for what it contains. We don’t inspect it and we don’t moderate it — that decision belongs to your product, before or after us.
What the service does, and what it doesn’t.
The pipeline starts with a complete file and ends with segments served to a player. It is not live ingest, not an editor, not a moderation service, and not a media rights platform. Those limits are described on the platform page, and they’re limits rather than a roadmap.
Signed, expiring links protect against casual sharing. If your obligations require studio-grade content protection, this isn’t the product for that, and we’d rather say so before you build.
Availability during the beta.
There’s no uptime figure on this site, and there isn’t one in the beta agreement either. What we commit to is behaviour: how each part of the system degrades, what keeps serving when a component is gone, and how you find out.
Work that could affect you is announced in your channel before it happens, with a window rather than a vague notice. Bulk imports are scheduled with us so that one team’s backlog doesn’t sit in front of another’s.
Changes to the API.
The documentation changes weekly, which is the honest state of a beta. What doesn’t change quietly is anything you’ve built against: breaking changes are announced with a date, in your channel, and the old behaviour keeps working through that window.
New fields can appear in responses and new event types can appear on your webhook endpoint. Handlers should ignore what they don’t recognise — that’s the one assumption we make about your code.
Money.
Commercial terms are agreed per team, in writing, before anything is billed. There’s no public price list during the beta because a price list implies a shape of usage we’re still learning.
Billing follows three units — encoding, storage, and delivery — and what drives each one is described on the pricing page rather than buried here.
Leaving.
You can download your masters at any time, including after you’ve told us you’re going. Deleting an account removes the assets and the playback IDs on the schedule described in the privacy page. Nothing about the design assumes you’ll stay, and that includes the exit.
We can end access for non-payment, for abuse of the platform, or for content that puts the delivery network at legal risk. If that happens you get told why, and you get your masters.
Liability, briefly.
The limits of what either side owes the other are set out in the signed agreement, in ordinary language, and we’re happy to walk through them line by line during onboarding. Summarising them here in one sentence would either be inaccurate or useless, so we don’t.
Questions about any of this belong in the first conversation.
Onboarding starts with talking, and this is a normal thing to talk about.
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.