Amba

Media

Media assets and folders — register an upload, browse, organize, delete.

Media assets register a filename + storage path and return a signed-style upload URL the client can PUT the file body to. Folders are a simple parent/child tree.

Endpoints

MethodPathDescription
POST/admin/projects/:projectId/mediaRegister an asset, get an upload_url.
GET/admin/projects/:projectId/mediaPaginated list; optional ?folder_id=.
DELETE/admin/projects/:projectId/media/:assetIdDelete an asset row.
POST/admin/projects/:projectId/media/foldersCreate a folder.
GET/admin/projects/:projectId/media/foldersList folders (optional ?parent_id=).
DELETE/admin/projects/:projectId/media/folders/:folderIdDelete a folder.
POST/admin/projects/:projectId/media/catalogsCreate a catalog.
GET/admin/projects/:projectId/media/catalogsList catalogs with item counts.
GET/admin/projects/:projectId/media/catalogs/:catalogIdGet a catalog + its ordered items.
PATCH/admin/projects/:projectId/media/catalogs/:catalogIdUpdate a catalog.
DELETE/admin/projects/:projectId/media/catalogs/:catalogIdDelete a catalog (items cascade).
POST/admin/projects/:projectId/media/catalogs/:catalogId/itemsAdd an asset to the catalog.
PATCH/admin/projects/:projectId/media/catalogs/:catalogId/items/reorderReorder items.
DELETE/admin/projects/:projectId/media/catalogs/:catalogId/items/:mediaIdRemove an asset.

POST /admin/projects/:projectId/media

Register a media asset. The storage path is <projectId>/<ms>_<filename>.

Request (CreateMediaAssetInput)

FieldTypeRequiredDefault
filenamestringyes
mime_typestringyes
size_bytesnumbernonull
folder_iduuidnonull
alt_textstringnonull
metadataobjectno{}

Response 201

{
  "data": {
    "id": "…",
    "filename": "…",
    "storage_url": "https://{projectId}.cdn.amba.host/media/…",
    "uploaded_by": "admin"
  },
  "upload_url": "https://{projectId}.cdn.amba.host/media/…?upload=true",
  "upload_url_expires_at": "2026-05-28T12:05:00Z"
}

Uploading the file

PUT the raw file bytes to the returned upload_url:

  • Method is PUT; the request body is the file bytes.
  • Content-Type MUST match the mime_type registered above — a mismatch is rejected.
  • No Authorization header on the upload PUTupload_url is already authorized.
  • Success is 200 or 204. The file is then served from storage_url.
  • upload_url is short-lived (upload_url_expires_at); if it has expired, register the asset again to get a fresh one.
  • Maximum file size for the media bucket is 50 MB.

Allowed MIME types

The default media bucket accepts the types below. A mime_type outside the list returns 400 MIME_NOT_ALLOWED.

CategoryAllowed types
Imageimage/jpeg, image/png, image/webp, image/gif
Videovideo/mp4, video/webm, video/quicktime, video/x-m4v
Audioaudio/mpeg, audio/aac, audio/ogg, audio/mp4

End-to-end example

# 1. Register the asset
RESP=$(curl -s -X POST '${BASE_URL}/admin/projects/{projectId}/media' \
  -H 'Authorization: Bearer ${DEV_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{"filename":"hero.png","mime_type":"image/png"}')
 
# 2. Extract upload + storage URLs
UPLOAD_URL=$(echo "$RESP" | jq -r '.upload_url')
STORAGE_URL=$(echo "$RESP" | jq -r '.data.storage_url')
 
# 3. PUT the bytes (Content-Type matches mime_type; no auth header)
curl -X PUT "$UPLOAD_URL" -H 'Content-Type: image/png' --data-binary @hero.png
 
# 4. Fetch the asset
curl -L "$STORAGE_URL" -o downloaded.png

Try it:

POST/admin/projects/%7B%7BprojectId%7D%7D/media
developer auth
curl -X POST 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X POST '${BASE_URL}/admin/projects/{projectId}/media' \
  -H 'Authorization: Bearer ${DEV_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{}'

GET /admin/projects/:projectId/media

Query

ParamDefaultDescription
limit50
offset0
folder_idRestrict to a folder.

Response 200

{
  "data": [{ "id": "…", "filename": "…", "mime_type": "image/png" }],
  "total": 100,
  "offset": 0,
  "limit": 50
}

Try it:

GET/admin/projects/%7B%7BprojectId%7D%7D/media
developer auth
curl -X GET 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X GET '${BASE_URL}/admin/projects/{projectId}/media' \
  -H 'Authorization: Bearer ${DEV_TOKEN}'

DELETE /admin/projects/:projectId/media/:assetId

{ "data": { "deleted": true } }

Try it:

DELETE/admin/projects/%7B%7BprojectId%7D%7D/media/%7B%7BassetId%7D%7D
developer auth
curl -X DELETE 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media/%7B%7BassetId%7D%7D'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X DELETE '${BASE_URL}/admin/projects/{projectId}/media/{assetId}' \
  -H 'Authorization: Bearer ${DEV_TOKEN}'

POST /admin/projects/:projectId/media/folders

Request (CreateMediaFolderInput)

FieldTypeRequired
namestringyes
parent_iduuidno

Response 201

{ "data": { "id": "…", "name": "…", "parent_id": null } }

Try it:

POST/admin/projects/%7B%7BprojectId%7D%7D/media/folders
developer auth
curl -X POST 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media/folders'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X POST '${BASE_URL}/admin/projects/{projectId}/media/folders' \
  -H 'Authorization: Bearer ${DEV_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{}'

GET /admin/projects/:projectId/media/folders

Query

ParamDescription
parent_idIf omitted, returns only root folders (parent_id IS NULL).

Try it:

GET/admin/projects/%7B%7BprojectId%7D%7D/media/folders
developer auth
curl -X GET 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media/folders'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X GET '${BASE_URL}/admin/projects/{projectId}/media/folders' \
  -H 'Authorization: Bearer ${DEV_TOKEN}'

DELETE /admin/projects/:projectId/media/folders/:folderId

{ "data": { "deleted": true } }

Try it:

DELETE/admin/projects/%7B%7BprojectId%7D%7D/media/folders/%7B%7BfolderId%7D%7D
developer auth
curl -X DELETE 'https://api.amba.dev/v1/admin/projects/%7B%7BprojectId%7D%7D/media/folders/%7B%7BfolderId%7D%7D'
Loading auth… Configure auth in the settings drawer (top-right) to run this request.

Curl:

curl -X DELETE '${BASE_URL}/admin/projects/{projectId}/media/folders/{folderId}' \
  -H 'Authorization: Bearer ${DEV_TOKEN}'

Catalogs

A catalog is a named, slug-addressable bundle of existing media assets your app reads in one call (Amba.media.catalog(slug)client read). It curates assets by reference — the item URLs are the same public asset URLs every other media read returns, not copies.

POST /admin/projects/:projectId/media/catalogs

FieldTypeRequiredDefaultNotes
slugstringyes/^[a-z0-9][a-z0-9-]{0,63}$/, unique per project
namestringyes
descriptionstringnonull
is_publicbooleannotrueOnly public catalogs are readable client-side.
metadataobjectno{}

A duplicate slug returns 409 SLUG_TAKEN. Response 201 echoes the catalog row.

POST /admin/projects/:projectId/media/catalogs/:catalogId/items

FieldTypeRequiredDefaultNotes
media_iduuidyesMust be an existing media asset.
positionnumberno0Lower sorts first.
captionstringnonullPer-catalog label for this asset.
metadataobjectno{}

Adding the same asset to a catalog twice returns 409 ALREADY_IN_CATALOG.

PATCH /admin/projects/:projectId/media/catalogs/:catalogId/items/reorder

Body { "items": [{ "media_id": "…", "position": 0 }, …] }. Each provided pair sets that item's position; assets not listed keep their current position.