# Video APIs that deliver output to your own bucket

Canonical: https://rendobar.com/blog/video-api-output-to-your-bucket/
Author: Abdelrahman Essawy
Published: 2026-09-13
Updated: 2026-09-13

---

## Key takeaways

- Owning the output means the file lands in your bucket, not in a vendor's. 8 of the 13 services we checked can write there, and one of those, Cloudinary, only keeps backup copies.
- Most of them want a long-lived access key. Coconut, Transcodely, Transloadit and Shotstack all take a key and a secret, and a key stays valid until someone rotates it.
- Three can write through an IAM role instead: AWS MediaConvert inside your own account, Bitmovin with an external ID, and Rendobar with a one-click role scoped to one bucket.
- Five keep outputs in their own storage and hand you a link: Mux, Rendi, RenderIO, FFmpeg Micro and Very Good FFmpeg. RenderIO's bring-your-own-bucket applies only to its video download API.
- Reading inputs from the bucket matters as much as writing. Five services read from it directly, and the rest take a URL, so a private object needs a presigned link that you mint and keep alive.

A video API that keeps your output in its own storage is fine until you need the
file somewhere else. Then every job ends with a download and an upload you run
yourself, a retention clock you didn't set, and a link that expires. The
alternative is an API that writes the finished file straight into a bucket you own.

Short version. We read the storage documentation of 13 video processing services.
**Eight can put output into your bucket**, one of them as backup copies only. Most
of those want a long-lived **access key**. **Three** can write through an **IAM
role** instead, and **five** keep outputs in their own storage and give you a link.

I build Rendobar, one of the services on this list, so weigh the framing
accordingly. Every row below comes from the vendor's own documentation, linked at
the end, as read on {VERIFIED_AT}.

_What each service needs from you before it can write into your bucket._

## The comparison

<div style="overflow-x:auto">
  <table>
    <thead>
      <tr>
        <th>Service</th>
        <th>Delivers to your bucket</th>
        <th>Where it can write</th>
        <th>How it gets access</th>
        <th>Reads inputs from it</th>
      </tr>
    </thead>
    <tbody>
      {STORAGE_VENDORS.map((v) => (
        <tr>
          <td><strong>{v.name}</strong></td>
          <td>{deliveryLabel[v.delivery]}{v.plan ? `, ${v.plan.toLowerCase()}` : ""}</td>
          <td>{v.providers.length ? v.providers.join(", ") : "None"}</td>
          <td>{v.accessNote}</td>
          <td>{readsLabel[v.reads]}</td>
        </tr>
      ))}
    </tbody>
  </table>
</div>

## Three ways a service gets into your bucket

The column that matters most is the fourth one, because it decides what you are
trusting a vendor to hold.

**An access key.** You create an IAM user, attach a policy, and paste its key and
secret into the vendor's dashboard. It is the simplest setup, and the key stays
valid until someone rotates it. If the vendor's copy leaks, whoever has it can write
to your bucket for as long as you don't notice.

**A cross-account role with an external ID.** You create a role in your account
that trusts the vendor's AWS account, with a condition requiring a value the vendor
generated for you. The vendor assumes the role and gets credentials that expire
within hours. AWS's documentation explains why the external ID is there: without
it, another customer who learns your role's ARN could ask the vendor to act on your
bucket, which AWS calls the confused deputy problem.

**A role federated through an identity provider.** You create a role that trusts a
signed identity token rather than an AWS account, with conditions naming exactly
which identity may assume it. Nothing long lived is shared at all. [How to let a
service write to your S3 bucket without access
keys](/blog/s3-access-without-access-keys/) walks through the trust policy line by
line.

## Services that write through a role

**AWS Elemental MediaConvert** is the native option, and it works through an IAM
service role in your own account. That makes it simple when the bucket and the
transcoder live in the same account. Writing into another account's bucket needs
a bucket policy or a canned ACL on top.

**Bitmovin** offers S3 role-based outputs alongside ordinary access keys. You create
the role, Bitmovin supplies an external ID for its trust policy, and its encoder
assumes the role to write. It also supports Google Cloud Storage, Azure, SFTP and
S3-compatible storage.

**Rendobar** creates the role for you. Picking Amazon S3 opens a CloudFormation
stack filled in for one bucket, and the connection completes when the stack reports
back. No access key is created, and deleting the stack revokes access. R2, Supabase
and other S3-compatible services connect with a token, a sign-in or a key pair,
since a role is an AWS concept.

## Services that take an access key

**Coconut** writes to the widest list of destinations here, from S3 and Google
Cloud Storage to Wasabi, Backblaze, Azure and FTP, with the key and secret passed
in each job's storage block. Its inputs are URLs.

**Transcodely** reads from and writes to S3, Google Cloud Storage and R2, with access
keys for S3 and R2 and a service account key file for Google Cloud Storage.

**Transloadit** stores with its `/s3/store` robot using a key and secret saved as
Template Credentials, and accepts an optional session token. A `host` parameter
points it at S3-compatible services. It also imports from S3.

**Shotstack** takes an access key ID and secret in its dashboard and can send
renders to several buckets at once, as long as they share one AWS account and one
set of credentials. It also delivers to Google Cloud Storage, Azure, Google Drive
and Vimeo. Source footage goes through its own ingest storage or a URL.

If you use one of these, give the key an IAM policy that allows writing to one
bucket and nothing else. A leaked key that can only put objects into a single
bucket is a far smaller incident than one attached to an administrator.

## Services that keep the output

**Mux** is a video platform first. Its outputs live in Mux, and master access
creates a temporary MP4 URL that expires after 24 hours for you to copy out.

**Rendi** stores FFmpeg outputs in its own storage and returns a `storage_url`.
**FFmpeg Micro** hands back a signed download URL that expires. **Very Good FFmpeg**
says output lands at a stable URL and does not mention your own bucket.

**RenderIO** stores FFmpeg outputs on its own R2. It does advertise bring-your-own
bucket for S3, R2 and Google Cloud Storage on its Growth plan and up, but that FAQ
belongs to its separate video download API.

**Cloudinary** sits between the groups. On paid plans it writes backup copies into
your S3, Google Cloud Storage or Azure bucket, allowlisted with a marker file. Those
are backups of what you uploaded, not deliveries of what a transformation produced.

None of this is a flaw for a platform whose product is hosting and playback. It
is a mismatch when the product you are building already has a bucket.

## Reading inputs from the bucket

Delivery is half the trip. Five services read inputs straight from your bucket, and
the others take a URL. A URL is fine for public files. For a private object it
means you mint a presigned link and keep it valid for as long as the job might
wait, which fails in a surprising way when the link was signed with an assumed
role. [Why S3 presigned URLs expire early](/blog/s3-presigned-url-expires-early/)
covers that trap.

## How to choose

Four questions settle most of it:

1. **Is your product hosting and playback?** Then a platform that keeps the output is
   doing its job, and delivery is beside the point.
2. **Does the output have to land in a bucket you own?** Cross off the five that keep
   it.
3. **Will your security review accept a long-lived key held by a vendor?** If not,
   the list is the three that use a role.
4. **Do your inputs live in the same bucket?** Prefer a service that reads from it,
   so private footage never needs a link you maintain.

For the raw FFmpeg side of this market on price, free tiers and agent access, see
[best FFmpeg API in 2026, compared](/blog/best-ffmpeg-api/). For the broader shape
of video tools, see [video processing API tools compared](/blog/video-processing-api/).

## Where this stops

Every row comes from documentation, read on {VERIFIED_AT}. We did not connect a
bucket to each service and test it, so a capability a vendor supports but does not
document is missing here, and one it documents but has since changed is stale. If
you spot either, the vendor's own page wins.

Plan gating is listed only where the docs state it. A blank does not mean every
plan includes the feature.

"Reads inputs from it" means the service reads a private object with credentials
you configured. Every service here can read a public URL, and any of them can read
a presigned one.

For how Rendobar connects a bucket, see the [storage connections guide](/docs/storage)
and the [connected storage changelog entry](/changelog/connected-storage/).
