File Assets API
Note
Requires Broadcast 2.48.0 or later.
The File Assets API manages the channel’s file library, the same files you see under File Assets in Broadcast. Each file has a public URL that never expires. Use the URL in emails and templates, or send it as the logo in the Brand Kit API.
The file library holds images: PNG, JPEG and GIF files under 10 MB.
Required Permissions
- File Assets read: list files and get a file
- File Assets write: upload and delete files
File Assets read and write are off on every token until you tick them, including tokens created before 2.48.0. Write does not include read: if an integration uploads and then lists files, tick both. Set the permissions under Access Tokens (and Admin API Tokens). See API Authentication.
A token without the permission gets 401 Unauthorized, the same as the other API endpoints:
{ "error": "Unauthorized" }
An admin API token must name the channel with broadcast_channel_id: as a query parameter for GET and DELETE, and in the body (or as a form field) for POST.
File Object
{ "id": 42, "filename": "logo.png", "content_type": "image/png", "byte_size": 18734, "url": "https://your-broadcast-domain.com/files/eyJfcmFpbHMi...--3f2a...-logo.png", "created_at": "2026-10-14T09:30:00Z" }
| Field | Type | Description |
|---|---|---|
id |
integer | The file’s ID. |
filename |
string | The file name, with its extension. |
content_type |
string | image/png, image/jpeg or image/gif. |
byte_size |
integer | The size of the file in bytes. |
url |
string | The public URL of the file. It never expires and needs no token. |
created_at |
string | When the file was uploaded (ISO 8601). |
Which Files a Channel Sees
A channel sees the files linked to it, and the files linked to no channel. This is the same rule as the File Assets page. A file of another channel is a 404.
When you upload a file, Broadcast links it to every channel, as the File Assets page does. Send channel_restricted: true to link it to the token’s channel only.
List Files
GET /api/v1/file_assets
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ "https://your-broadcast-domain.com/api/v1/file_assets?limit=20"
| Parameter | Description |
|---|---|
filter |
Finds files by file name. The closest matches come first. |
limit |
The number of files to return, from 1 to 1000. Another value is a 422. |
offset |
The number of files to skip, 0 or more. Another value is a 422. |
Without limit, the response holds every matching file. Without filter, the newest files come first.
{ "data": [ { "id": 42, "filename": "logo.png", "content_type": "image/png", "byte_size": 18734, "url": "https://your-broadcast-domain.com/files/eyJfcmFpbHMi...--3f2a...-logo.png", "created_at": "2026-10-14T09:30:00Z" } ], "total": 1 }
total counts every file that matches, before limit and offset.
Get a File
GET /api/v1/file_assets/:id
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ https://your-broadcast-domain.com/api/v1/file_assets/42
Returns 200 with the file object. A file that does not exist, or that the channel cannot see, returns 404:
{ "error": "File asset not found" }
Upload a File
POST /api/v1/file_assets
Send the file in one of two ways. Both return 201 with the file object.
As a multipart upload
Send multipart/form-data with the file in a file part. The file name and the content type come from the part.
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -F "file=@logo.png;type=image/png" \ https://your-broadcast-domain.com/api/v1/file_assets
As base64 in a JSON body
Send the bytes base64-encoded in data. Use this form when your client cannot send multipart, for example an AI agent through the MCP server.
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ --data-raw "{ \"filename\": \"logo.png\", \"content_type\": \"image/png\", \"data\": \"$(base64 < logo.png | tr -d '\n')\" }" \ https://your-broadcast-domain.com/api/v1/file_assets
| Field | Required | Description |
|---|---|---|
filename |
Yes | The file name, with its extension, such as logo.png. Broadcast keeps only the last part of a path, so images/logo.png is stored as logo.png. |
data |
Yes | The file, base64-encoded (standard alphabet, with padding). Broadcast ignores line breaks and spaces. |
content_type |
No | image/png, image/jpeg or image/gif. When you leave it out, Broadcast finds the type from the bytes and the file name. |
channel_restricted |
No | true links the file to the token’s channel only. The default is false. Also accepted as a multipart form field. Any value other than true or false (or "true", "false", 1, 0) is a 422. |
Broadcast never downloads a file from a URL. Upload the bytes.
Safe retries
Send an Idempotency-Key header to make a retry safe. Broadcast keeps the first response for 24 hours and returns it again for the same key, with the Idempotency-Replayed: true header, so the file is stored only once. The same key with a different body is a 422. See Transactional Email API for the full rules.
Errors
A 422 stores nothing:
- The data is not valid base64.
- The file is 10 MB or larger.
- The file is not a PNG, JPEG or GIF image.
- The body has neither a
filepart nordata, ordatahas nofilename. channel_restrictedis nottrueorfalse.
{ "error": "Unprocessable Content", "message": "data is not valid base64" }
{ "error": "Stored file has an invalid content type (authorized content types are PNG, JPG, GIF)" }
A key that the endpoint does not know is ignored with an unrecognized_parameter warning (see API Response Warnings).
Delete a File
DELETE /api/v1/file_assets/:id
curl -X DELETE \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ https://your-broadcast-domain.com/api/v1/file_assets/42
{ "message": "File asset deleted successfully" }
Warning
Emails that were already sent show the file from its URL. After you delete the file, those emails show a broken image.
You cannot delete a file that is a channel’s brand kit logo. Broadcast returns a 422:
{ "error": "This file is the channel's Brand Kit logo. Choose another logo (or none) in Settings > Brand Kit or with PATCH /api/v1/channel/design, then delete the file." }
When the file is the logo of another channel, the message is different:
{ "error": "This file is the Brand Kit logo of another channel. Choose another logo for that channel, then delete the file." }
Set another logo (or null) with the Brand Kit API first.
Set the Brand Kit Logo
- Upload the image with
POST /api/v1/file_assets. - Send the
urlfrom the response aschannel_design.brand.logo_urltoPATCH /api/v1/channel/design.
{ "channel_design": { "brand": { "logo_url": "https://your-broadcast-domain.com/files/eyJfcmFpbHMi...--3f2a...-logo.png" } } }
The logo must be linked to the channel. An upload without channel_restricted is linked to every channel, so any channel can use it as the logo.