Media

4 endpoints

Images, video and audio in the workspace's media library. Upload a file here, then give its id as a notification's media_asset_id. Which kinds you can upload depends on the plan.

List media#

GET/media
Needs media:read

Newest first.

Query parameters

cursor
string

An opaque value from a previous page's meta.next_cursor. Omit for the first page.

limit
integer

How many to return, up to 100.

Default: 20
type
string

Only image, video or audio.

Responses

200
200 response
{
  "data": [
    {
      "id": "0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d7001",
      "name": "flat-white.jpg",
      "type": "image",
      "mime_type": "image/jpeg",
      "size_bytes": 248113,
      "width": 1200,
      "height": 800,
      "duration_seconds": null,
      "source": "upload",
      "url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/flat-white.jpg",
      "thumbnail_url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/thumb.jpg",
      "created_at": "2026-09-20T09:12:00+00:00",
      "updated_at": "2026-09-20T09:12:00+00:00"
    }
  ],
  "meta": {
    "next_cursor": null
  }
}
Response fields
data
MediaAssetResource[]
required
data[].id
string
required
data[].name
string
required
data[].type
string
required
data[].mime_type
string
required
data[].size_bytes
integer
required
data[].width
integer | null
required
data[].height
integer | null
required
data[].duration_seconds
integer | null
required
data[].source
string
required
data[].url
string | null
required
data[].thumbnail_url
string | null
required
data[].created_at
string | null
required
data[].updated_at
string | null
required
meta
object
required
meta.next_cursor
string | null
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_revokedtoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token. Check it was copied in full, and that it is for this environment.

  • token_revoked

    The token "Zapier" was revoked on 2026-10-06 at 18:27 UTC. Issue a new one from Configuration › Platform API.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilityplatform_api_not_enabledwrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • platform_api_not_enabled

    The full Platform API isn't enabled for this workspace yet. Contact customer services to turn it on.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

invalid_parameterinvalid_cursor
  • invalid_parameter

    updated_since must be a valid date.

  • invalid_cursor

    That cursor is invalid or has expired.

422 response
{
  "error": {
    "code": "invalid_parameter",
    "message": "updated_since must be a valid date.",
    "fields": {
      "updated_since": [
        "Must be a valid date."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/media?limit=20' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/media?limit=20', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/media?limit=20',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/media?limit=20', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Upload a media file#

POST/media
Needs media:write

A multipart/form-data request with the file (up to 50 MB: a JPEG, PNG, GIF or WebP image, an MP4, MOV or WebM video, or an MP3, M4A, WAV or OGG audio file) and an optional name (the file's own name otherwise). An image's thumbnail is made a few seconds later. A Sandbox holds a limited amount of media in total.

Headers

Idempotency-Key
string

A unique value (e.g. a UUID) for this change. A retry with the same key within 24 hours gets the first response back, with Idempotent-Replayed: true, instead of making the change again.

Request body

multipart/form-dataStoreMediaAssetRequestrequired
file
string (binary)
required

Maximum file size: 51200 kilobytes.

name
string | null

Responses

201
201 response
{
  "data": {
    "id": "0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d7001",
    "name": "flat-white.jpg",
    "type": "image",
    "mime_type": "image/jpeg",
    "size_bytes": 248113,
    "width": 1200,
    "height": 800,
    "duration_seconds": null,
    "source": "upload",
    "url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/flat-white.jpg",
    "thumbnail_url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/thumb.jpg",
    "created_at": "2026-09-20T09:12:00+00:00",
    "updated_at": "2026-09-20T09:12:00+00:00"
  }
}
Response fields
data
MediaAssetResource
required
data.id
string
required
data.name
string
required
data.type
string
required
data.mime_type
string
required
data.size_bytes
integer
required
data.width
integer | null
required
data.height
integer | null
required
data.duration_seconds
integer | null
required
data.source
string
required
data.url
string | null
required
data.thumbnail_url
string | null
required
data.created_at
string | null
required
data.updated_at
string | null
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_revokedtoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token. Check it was copied in full, and that it is for this environment.

  • token_revoked

    The token "Zapier" was revoked on 2026-10-06 at 18:27 UTC. Issue a new one from Configuration › Platform API.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilityplatform_api_not_enabledwrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • platform_api_not_enabled

    The full Platform API isn't enabled for this workspace yet. Contact customer services to turn it on.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
409

A request with the same Idempotency-Key is still running (retry after Retry-After seconds), or the change conflicts with something that depends on it.

request_in_progress
  • request_in_progress

    This request is still being handled. Try again shortly.

409 response
{
  "error": {
    "code": "request_in_progress",
    "message": "This request is still being handled. Try again shortly."
  }
}
422

Something in the request isn't valid. fields says what, with the dashboard's wording.

validation_failed
  • validation_failed

    The given data was invalid.

422 response
{
  "error": {
    "code": "validation_failed",
    "message": "The given data was invalid.",
    "fields": {
      "name": [
        "The name field is required."
      ]
    }
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl -X POST 'https://api.bubbl.tech/platform/v1/media' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  --data '[object Object]'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/media', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
    'Content-Type': 'multipart/form-data',
  },
  body: '[object Object]',
});

const data = await response.json();
Request
import requests

response = requests.request(
    'POST',
    'https://api.bubbl.tech/platform/v1/media',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
        'Content-Type': 'multipart/form-data',
    },
    data='[object Object]',
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.bubbl.tech/platform/v1/media', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
        'Content-Type' => 'multipart/form-data',
    ],
    'body' => '[object Object]',
]);

$data = json_decode((string) $response->getBody(), true);

Get a media file#

GET/media/{media}
Needs media:read

Path parameters

media
string (uuid)
required

The media ID

Responses

200
200 response
{
  "data": {
    "id": "0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d7001",
    "name": "flat-white.jpg",
    "type": "image",
    "mime_type": "image/jpeg",
    "size_bytes": 248113,
    "width": 1200,
    "height": 800,
    "duration_seconds": null,
    "source": "upload",
    "url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/flat-white.jpg",
    "thumbnail_url": "https://media.bubbl.tech/media/0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d0001/3f1c9e2a-7b4d-4e8f-a1c2-5d6e7f8a9b0c/thumb.jpg",
    "created_at": "2026-09-20T09:12:00+00:00",
    "updated_at": "2026-09-20T09:12:00+00:00"
  }
}
Response fields
data
MediaAssetResource
required
data.id
string
required
data.name
string
required
data.type
string
required
data.mime_type
string
required
data.size_bytes
integer
required
data.width
integer | null
required
data.height
integer | null
required
data.duration_seconds
integer | null
required
data.source
string
required
data.url
string | null
required
data.thumbnail_url
string | null
required
data.created_at
string | null
required
data.updated_at
string | null
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_revokedtoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token. Check it was copied in full, and that it is for this environment.

  • token_revoked

    The token "Zapier" was revoked on 2026-10-06 at 18:27 UTC. Issue a new one from Configuration › Platform API.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilityplatform_api_not_enabledwrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • platform_api_not_enabled

    The full Platform API isn't enabled for this workspace yet. Contact customer services to turn it on.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
404

Nothing with that ID in this workspace.

not_found
  • not_found

    No such resource in this workspace.

404 response
{
  "error": {
    "code": "not_found",
    "message": "No such resource in this workspace."
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl 'https://api.bubbl.tech/platform/v1/media/{media}' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/media/{media}', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'GET',
    'https://api.bubbl.tech/platform/v1/media/{media}',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.bubbl.tech/platform/v1/media/{media}', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);

Delete a media file#

DELETE/media/{media}
Needs media:write

Refused (409 media_in_use) while a notification uses it: change those notifications' media_asset_id first.

Path parameters

media
string (uuid)
required

The media ID

Headers

Idempotency-Key
string

A unique value (e.g. a UUID) for this change. A retry with the same key within 24 hours gets the first response back, with Idempotent-Replayed: true, instead of making the change again.

Responses

200
200 response
{
  "data": {
    "id": "0192f0a4-6b1e-7c3a-9d2f-5e8b1a4d7001",
    "deleted": true
  }
}
Response fields
data
object
required
data.id
string
required
data.deleted
boolean
required
401

The token is missing, unknown, revoked or expired.

missing_tokeninvalid_tokentoken_revokedtoken_expired
  • missing_token

    Missing bearer token.

  • invalid_token

    Unknown API token. Check it was copied in full, and that it is for this environment.

  • token_revoked

    The token "Zapier" was revoked on 2026-10-06 at 18:27 UTC. Issue a new one from Configuration › Platform API.

  • token_expired

    This token has expired. Issue a new one from Configuration › Platform API.

401 response
{
  "error": {
    "code": "missing_token",
    "message": "Missing bearer token."
  }
}
403

The token or workspace can't do this.

missing_abilityplatform_api_not_enabledwrong_environmentworkspace_paused
  • missing_ability

    This token doesn't have the campaigns:write scope.

  • platform_api_not_enabled

    The full Platform API isn't enabled for this workspace yet. Contact customer services to turn it on.

  • wrong_environment

    This is a Sandbox token: use the Sandbox API address. https://api.sandbox.bubbl.tech/platform/v1

  • workspace_paused

    This workspace is scheduled for deletion; its API access is paused.

403 response
{
  "error": {
    "code": "missing_ability",
    "message": "This token doesn't have the campaigns:write scope."
  }
}
404

Nothing with that ID in this workspace.

not_found
  • not_found

    No such resource in this workspace.

404 response
{
  "error": {
    "code": "not_found",
    "message": "No such resource in this workspace."
  }
}
409

A request with the same Idempotency-Key is still running (retry after Retry-After seconds), or the change conflicts with something that depends on it.

request_in_progressmedia_in_use
  • request_in_progress

    This request is still being handled. Try again shortly.

  • media_in_use

    Notifications use this file; change their media first: 0199a3b2-5c1e-7f42-9d10-3e8b2a6c4f01.

409 response
{
  "error": {
    "code": "request_in_progress",
    "message": "This request is still being handled. Try again shortly."
  }
}
429

Too many requests. Wait for the number of seconds in Retry-After.

rate_limitedtoo_many_failed_attempts
  • rate_limited

    Too many requests. Slow down and try again shortly.

  • too_many_failed_attempts

    Too many failed attempts. Try again shortly.

429 response
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Slow down and try again shortly."
  }
}
Request
curl -X DELETE 'https://api.bubbl.tech/platform/v1/media/{media}' \
  -H 'Authorization: Bearer bubbl_YOUR_TOKEN' \
  -H 'Accept: application/json'
Request
const response = await fetch('https://api.bubbl.tech/platform/v1/media/{media}', {
  method: 'DELETE',
  headers: {
    Authorization: 'Bearer bubbl_YOUR_TOKEN',
    Accept: 'application/json',
  },
});

const data = await response.json();
Request
import requests

response = requests.request(
    'DELETE',
    'https://api.bubbl.tech/platform/v1/media/{media}',
    headers={
        'Authorization': 'Bearer bubbl_YOUR_TOKEN',
        'Accept': 'application/json',
    },
)
response.raise_for_status()
data = response.json()
Request
<?php

$client = new \GuzzleHttp\Client();

$response = $client->request('DELETE', 'https://api.bubbl.tech/platform/v1/media/{media}', [
    'headers' => [
        'Authorization' => 'Bearer bubbl_YOUR_TOKEN',
        'Accept' => 'application/json',
    ],
]);

$data = json_decode((string) $response->getBody(), true);