---
title: "Media API Reference"
description: "Endpoints for managing media files in Linkbreakers. These endpoints allow you to upload, retrieve, list, and delete media files for your workspace."
canonical: "https://linkbreakers.com/help/api/media"
---

# Media

Endpoints for managing media files in Linkbreakers. These endpoints allow you to upload, retrieve, list, and delete media files for your workspace.

## Media

## [#](#media-object)The Media object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

createdAt

string (date-time)

When the file was created

fileName

string

The name of the file

id

string

The unique identifier of the media file (UUID)

kind

string (enum)

What kind of file this is

##### Allowed values

`KIND_UNSPECIFIED`

Not set

`KIND_IMAGE`

A PNG, JPEG, WebP or SVG image

`KIND_DOCUMENT`

A PDF document

`KIND_VIDEO`

An MP4 video

mediaType

string (enum)

Deprecated: the value recorded at upload, kept for older clients. See UploadOrigin.

##### Allowed values

`TYPE_UNSPECIFIED`

The media type is not specified

`TYPE_CENTRAL_QRCODE_IMAGE`

The media type is a central QR code image

`TYPE_BACKGROUND_COVER`

The media type is a background cover for page themes

`TYPE_BADGE`

The media type is a badge image for page themes

`TYPE_FOOTER_LOGO`

The media type is a footer logo shown at the bottom of page theme pages

`TYPE_OPEN_MEDIA`

The media is handed to visitors by an Open media workflow step

mimeType

string

The MIME type of the file

references

array<object>

Where this media is used: the Open media steps opening it, the page themes showing it and the QR code designs using it as their logo, each named by the link or the template it belongs to. Empty means it is not used anywhere. Filled by List and Get; Create, CreateUpload and CompleteUpload return it empty. Deleting media an Open media step or a page theme uses is refused with MEDIA\_IN\_USE; a QR code keeps its own copy of its logo, so deleting the media changes no QR code and only clears its link to it.

sha256

string

The SHA-256 of the file's bytes, 64 lowercase hexadecimal characters, computed by the server. A workspace holds each file once: uploading bytes with the same hash is refused with 409 MEDIA\_ALREADY\_EXISTS, naming this media in the error's existingMediaId and existingFileName metadata. Empty while pending, and for media stored before files were hashed.

signedUrl

string

Short-lived signed URL for downloading the media asset

size

integer (int64)

The size of the file in bytes

status

string (enum)

Status says whether the file behind a media item is stored yet

##### Allowed values

`STATUS_UNSPECIFIED`

Not set

`STATUS_PENDING`

A direct upload that has not been completed: no file yet, not listed, cannot be used

`STATUS_READY`

Stored and checked, ready to use

updatedAt

string (date-time)

When the file was last updated

uploadedBy

string

The member who uploaded the file If it was uploaded through the public API, or if the member was removed from the workspace, the uploaded\_by will be null.

uploadedFrom

string (enum)

UploadOrigin is where in the product a media item was uploaded from. It is information only, so pickers can show a section's own uploads first; it never limits where the media can be used. To add a place, add a value here (next number), map it in core, and pass it from the screen that uploads.

##### Allowed values

`UPLOAD_ORIGIN_UNSPECIFIED`

Not set. Uploads that do not say where they come from are recorded as UPLOAD\_ORIGIN\_MEDIA\_LIBRARY.

`UPLOAD_ORIGIN_MEDIA_LIBRARY`

Uploaded from the media library itself

`UPLOAD_ORIGIN_QR_CODE_LOGO`

Uploaded while picking a QR code's logo

`UPLOAD_ORIGIN_BACKGROUND_COVER`

Uploaded while picking a page theme's background cover

`UPLOAD_ORIGIN_BADGE`

Uploaded while picking a page theme's badge

`UPLOAD_ORIGIN_FOOTER_LOGO`

Uploaded while picking a page theme's footer logo

`UPLOAD_ORIGIN_OPEN_MEDIA`

Uploaded while picking the media an Open media step opens

`UPLOAD_ORIGIN_ASSISTANT`

Imported by the Assistant, from a file attached to a conversation or a URL

usage

string (enum)

Deprecated: the value recorded at upload, kept for older clients. It no longer limits anything. Uploads accept images (PNG, JPEG, WebP, SVG) up to 10 MB, PDF documents up to 25 MB and MP4 videos up to 50 MB, whatever the usage. Where media is used is checked when it is attached: a QR code logo, background cover, badge or footer logo must be an image of at most 3 MB; an Open media step takes any media.

##### Allowed values

`USAGE_UNSPECIFIED`

Not set

`USAGE_CENTRAL_QRCODE_IMAGE`

The logo in the center of a QR code

`USAGE_BACKGROUND_COVER`

A page theme's background cover

`USAGE_BADGE`

A page theme's badge image

`USAGE_FOOTER_LOGO`

A page theme's footer logo

`USAGE_OPEN_MEDIA`

Media an Open media workflow step hands to visitors: a PDF menu or brochure, an image or an MP4 video

visibility

string (enum)

The media visibility is not specified

##### Allowed values

`VISIBILITY_UNSPECIFIED`

Media visibility not specified

`VISIBILITY_PUBLIC`

The media visibility is public

`VISIBILITY_PRIVATE`

The media visibility is private

workspaceId

string

The workspace ID the media file belongs to (UUID)

[Learn moreLearn more about media files in Linkbreakers](https://linkbreakers.com/help/article/whats-a-media)

Example object

```json
{
  "createdAt": "2026-10-25T05:41:07.910Z",
  "fileName": "string",
  "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
  "kind": "KIND_UNSPECIFIED",
  "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
  "mimeType": "string",
  "references": [
    {
      "linkId": "string",
      "linkName": "string",
      "pageThemeTemplateId": "string",
      "pageThemeTemplateName": "string",
      "qrcodeTemplateId": "string",
      "qrcodeTemplateName": "string",
      "type": "TYPE_UNSPECIFIED",
      "workflowStepId": "string"
    }
  ],
  "sha256": "string",
  "signedUrl": "https://example.com",
  "size": 0,
  "status": "STATUS_UNSPECIFIED",
  "updatedAt": "2026-10-25T05:41:07.910Z",
  "uploadedBy": "string",
  "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
  "usage": "USAGE_UNSPECIFIED",
  "visibility": "VISIBILITY_PRIVATE",
  "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
}
```

GET

`/v1/media`

Requires auth

## [#](#list-media-files)List media files

Retrieves the workspace's ready media files, newest first, optionally narrowed to one kind or to where they were uploaded from. total\_count is every item matching the filters across all pages. Each item lists its references: where it is used. Requires the \`media:read\` scope.

### [#](#list-media-files-parameters)Parameters

#### query parameters

pageSize

integer (int64)

Required

query

The maximum number of media files to return.

pageToken

string

query

The token for retrieving the next page of results If not provided, the first page of results will be returned

usage

string

query

Deprecated: filter by uploaded\_from instead. Still matches the value recorded at upload, which says nothing about where the media is used.

##### Allowed values

`USAGE_UNSPECIFIED`

Not set

`USAGE_CENTRAL_QRCODE_IMAGE`

The logo in the center of a QR code

`USAGE_BACKGROUND_COVER`

A page theme's background cover

`USAGE_BADGE`

A page theme's badge image

`USAGE_FOOTER_LOGO`

A page theme's footer logo

`USAGE_OPEN_MEDIA`

Media an Open media workflow step hands to visitors: a PDF menu or brochure, an image or an MP4 video

kind

string

query

Only media of this kind. Unset lists every kind.

##### Allowed values

`KIND_UNSPECIFIED`

Not set

`KIND_IMAGE`

A PNG, JPEG, WebP or SVG image

`KIND_DOCUMENT`

A PDF document

`KIND_VIDEO`

An MP4 video

uploadedFrom

string

query

Only media uploaded from this place. Unset lists media from everywhere. Where media was uploaded from says nothing about where it can be used: read references for that.

##### Allowed values

`UPLOAD_ORIGIN_UNSPECIFIED`

Not set. Uploads that do not say where they come from are recorded as UPLOAD\_ORIGIN\_MEDIA\_LIBRARY.

`UPLOAD_ORIGIN_MEDIA_LIBRARY`

Uploaded from the media library itself

`UPLOAD_ORIGIN_QR_CODE_LOGO`

Uploaded while picking a QR code's logo

`UPLOAD_ORIGIN_BACKGROUND_COVER`

Uploaded while picking a page theme's background cover

`UPLOAD_ORIGIN_BADGE`

Uploaded while picking a page theme's badge

`UPLOAD_ORIGIN_FOOTER_LOGO`

Uploaded while picking a page theme's footer logo

`UPLOAD_ORIGIN_OPEN_MEDIA`

Uploaded while picking the media an Open media step opens

`UPLOAD_ORIGIN_ASSISTANT`

Imported by the Assistant, from a file attached to a conversation or a URL

cursor

string

query

Opaque cursor from the previous page's nextPageToken. Same as pageToken; when both are sent, pageToken wins.

### [#](#list-media-files-response)Response

200

Everything worked as expected.

media

array<object>

Page of media entries including fresh signed URLs

nextPageToken

string

Cursor to continue listing media assets

totalCount

integer (int64)

Every media item matching the filters, across all pages

### [#](#list-media-files-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X GET "https://api.linkbreakers.com/v1/media?pageSize={pageSize}&pageToken={pageToken}&usage={usage}&kind={kind}&uploadedFrom={uploadedFrom}&cursor={cursor}" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Typical response

```json
{
  "media": [
    {
      "createdAt": "2026-10-25T05:41:07.904Z",
      "fileName": "string",
      "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
      "kind": "KIND_UNSPECIFIED",
      "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
      "mimeType": "string",
      "references": [
        {}
      ],
      "sha256": "string",
      "signedUrl": "https://example.com",
      "size": 0,
      "status": "STATUS_UNSPECIFIED",
      "updatedAt": "2026-10-25T05:41:07.904Z",
      "uploadedBy": "string",
      "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
      "usage": "USAGE_UNSPECIFIED",
      "visibility": "VISIBILITY_PRIVATE",
      "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
    }
  ],
  "nextPageToken": "eyJtZWRpYUlkIjoiNWIifQ==",
  "totalCount": 0
}
```

Base URL: `https://api.linkbreakers.com`

GET

`/v1/media/{id}`

Requires auth

## [#](#get-media-file-details)Get media file details

Retrieves information about a media file including its metadata and URL. Example: Getting details for media with ID "med\_123". Requires the \`media:read\` scope.

### [#](#get-media-file-details-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the media file to retrieve (UUID)

### [#](#get-media-file-details-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

### [#](#get-media-file-details-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X GET "https://api.linkbreakers.com/v1/media/{id}" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.906Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.907Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  }
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media`

Requires auth

## [#](#upload-a-media-file)Upload a media file

Uploads a file sent in the request itself, base64 encoded over HTTP, up to 3 MB. Larger files (a PDF brochure, a video) are uploaded straight to storage instead: CreateUpload, a PUT of the file to the returned upload\_url, then CompleteUpload. A media item only has a kind, read from its bytes: images (PNG, JPEG, WebP, SVG) up to 10 MB, PDF documents up to 25 MB and MP4 videos up to 50 MB. Nothing about where it will be used is needed at upload: any image can then be a QR code logo, a background cover, a badge or a footer logo (up to 3 MB for those), and any media can be opened by an Open media step. A workspace holds each file once. A file whose bytes (SHA-256) match media the workspace already has is refused with 409 MEDIA\_ALREADY\_EXISTS; the error's metadata names that media in existingMediaId and existingFileName. Use that media instead of uploading the file again. Requires the \`media:write\` scope.

### [#](#upload-a-media-file-parameters)Parameters

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#upload-a-media-file-request)Request body

fileData

string

The file data to upload, at most 3 MB. It must be transmitted in a base64 string format when sending it through HTTP. Accepted formats are PNG, JPEG, WebP and SVG images, PDF documents and MP4 videos. Larger files go through CreateUpload.

fileName

string

The name of the file

mediaType

string (enum)

Deprecated: the value recorded at upload, kept for older clients. See UploadOrigin.

##### Allowed values

`TYPE_UNSPECIFIED`

The media type is not specified

`TYPE_CENTRAL_QRCODE_IMAGE`

The media type is a central QR code image

`TYPE_BACKGROUND_COVER`

The media type is a background cover for page themes

`TYPE_BADGE`

The media type is a badge image for page themes

`TYPE_FOOTER_LOGO`

The media type is a footer logo shown at the bottom of page theme pages

`TYPE_OPEN_MEDIA`

The media is handed to visitors by an Open media workflow step

uploadedFrom

string (enum)

UploadOrigin is where in the product a media item was uploaded from. It is information only, so pickers can show a section's own uploads first; it never limits where the media can be used. To add a place, add a value here (next number), map it in core, and pass it from the screen that uploads.

##### Allowed values

`UPLOAD_ORIGIN_UNSPECIFIED`

Not set. Uploads that do not say where they come from are recorded as UPLOAD\_ORIGIN\_MEDIA\_LIBRARY.

`UPLOAD_ORIGIN_MEDIA_LIBRARY`

Uploaded from the media library itself

`UPLOAD_ORIGIN_QR_CODE_LOGO`

Uploaded while picking a QR code's logo

`UPLOAD_ORIGIN_BACKGROUND_COVER`

Uploaded while picking a page theme's background cover

`UPLOAD_ORIGIN_BADGE`

Uploaded while picking a page theme's badge

`UPLOAD_ORIGIN_FOOTER_LOGO`

Uploaded while picking a page theme's footer logo

`UPLOAD_ORIGIN_OPEN_MEDIA`

Uploaded while picking the media an Open media step opens

`UPLOAD_ORIGIN_ASSISTANT`

Imported by the Assistant, from a file attached to a conversation or a URL

usage

string (enum)

Deprecated: the value recorded at upload, kept for older clients. It no longer limits anything. Uploads accept images (PNG, JPEG, WebP, SVG) up to 10 MB, PDF documents up to 25 MB and MP4 videos up to 50 MB, whatever the usage. Where media is used is checked when it is attached: a QR code logo, background cover, badge or footer logo must be an image of at most 3 MB; an Open media step takes any media.

##### Allowed values

`USAGE_UNSPECIFIED`

Not set

`USAGE_CENTRAL_QRCODE_IMAGE`

The logo in the center of a QR code

`USAGE_BACKGROUND_COVER`

A page theme's background cover

`USAGE_BADGE`

A page theme's badge image

`USAGE_FOOTER_LOGO`

A page theme's footer logo

`USAGE_OPEN_MEDIA`

Media an Open media workflow step hands to visitors: a PDF menu or brochure, an image or an MP4 video

visibility

string (enum)

The media visibility is not specified

##### Allowed values

`VISIBILITY_UNSPECIFIED`

Media visibility not specified

`VISIBILITY_PUBLIC`

The media visibility is public

`VISIBILITY_PRIVATE`

The media visibility is private

### [#](#upload-a-media-file-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

### [#](#upload-a-media-file-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{"fileData":"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==","fileName":"example.jpg","mediaType":"TYPE_UNSPECIFIED","uploadedFrom":"UPLOAD_ORIGIN_UNSPECIFIED","usage":"USAGE_UNSPECIFIED","visibility":"VISIBILITY_UNSPECIFIED"}'
```

Sample payload (application/json)

```json
{
  "fileData": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==",
  "fileName": "example.jpg",
  "mediaType": "TYPE_UNSPECIFIED",
  "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
  "usage": "USAGE_UNSPECIFIED",
  "visibility": "VISIBILITY_UNSPECIFIED"
}
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.905Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.905Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  }
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media:import`

Requires auth

## [#](#import-a-media-file-from-a-url)Import a media file from a URL

Fetches a file server-side and stores it as a READY media item, so a file that is already online, or one attached to an Assistant conversation, never has to be downloaded and uploaded again. Give exactly one source: url, a public https address the file is downloaded from, or assistant\_attachment\_id, a file the caller attached to their own Assistant conversation. The kind is read from the file's bytes, never from its name or a Content-Type header, and the same limits as every upload apply: images (PNG, JPEG, WebP, SVG) up to 10 MB, PDF documents up to 25 MB and MP4 videos up to 50 MB, within the workspace's media storage allowance. A URL must be https on port 443 and resolve to a public address; redirects are followed only to other such URLs, at most five. A workspace holds each file once. A file whose bytes (SHA-256) match media the workspace already has is refused with 409 MEDIA\_ALREADY\_EXISTS; the error's metadata names that media in existingMediaId and existingFileName. Use that media instead of uploading the file again. Requires the \`media:write\` scope.

### [#](#import-a-media-file-from-a-url-parameters)Parameters

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#import-a-media-file-from-a-url-request)Request body

assistantAttachmentId

string

The id of a file the caller attached to their own Assistant conversation. Attachments are short-lived and belong to the member who attached them, in that workspace.

fileName

string

The name shown in the media library and as the file name visitors download. Empty takes the attachment's name, or the last segment of the URL's path.

uploadedFrom

string (enum)

UploadOrigin is where in the product a media item was uploaded from. It is information only, so pickers can show a section's own uploads first; it never limits where the media can be used. To add a place, add a value here (next number), map it in core, and pass it from the screen that uploads.

##### Allowed values

`UPLOAD_ORIGIN_UNSPECIFIED`

Not set. Uploads that do not say where they come from are recorded as UPLOAD\_ORIGIN\_MEDIA\_LIBRARY.

`UPLOAD_ORIGIN_MEDIA_LIBRARY`

Uploaded from the media library itself

`UPLOAD_ORIGIN_QR_CODE_LOGO`

Uploaded while picking a QR code's logo

`UPLOAD_ORIGIN_BACKGROUND_COVER`

Uploaded while picking a page theme's background cover

`UPLOAD_ORIGIN_BADGE`

Uploaded while picking a page theme's badge

`UPLOAD_ORIGIN_FOOTER_LOGO`

Uploaded while picking a page theme's footer logo

`UPLOAD_ORIGIN_OPEN_MEDIA`

Uploaded while picking the media an Open media step opens

`UPLOAD_ORIGIN_ASSISTANT`

Imported by the Assistant, from a file attached to a conversation or a URL

url

string

A public https URL the file is downloaded from, on port 443\. Redirects are followed only to other public https URLs, at most five. The file's kind is read from its bytes.

### [#](#import-a-media-file-from-a-url-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

### [#](#import-a-media-file-from-a-url-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media:import" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{"assistantAttachmentId":"string","fileName":"menu.pdf","uploadedFrom":"UPLOAD_ORIGIN_UNSPECIFIED","url":"https://example.com/menu.pdf"}'
```

Sample payload (application/json)

```json
{
  "assistantAttachmentId": "string",
  "fileName": "menu.pdf",
  "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
  "url": "https://example.com/menu.pdf"
}
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.909Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.909Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  }
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media/{id}:complete`

Requires auth

## [#](#complete-a-direct-media-upload)Complete a direct media upload

Checks the file PUT to the upload\_url: its size, its real format read from its first bytes, and the storage allowance. When it matches what CreateUpload declared, the media becomes READY and is returned with a signed URL. When it does not, the file and the media are discarded and the error says why; start a new upload. Completing a media item that is already READY returns it. The server always establishes the file's SHA-256 itself, from the checksum storage verified or by reading the file back. A file the workspace already holds is discarded with 409 MEDIA\_ALREADY\_EXISTS; the error's metadata names the existing media in existingMediaId and existingFileName. Use that media instead. Requires the \`media:write\` scope.

### [#](#complete-a-direct-media-upload-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the pending media item (UUID), from CreateUpload

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#complete-a-direct-media-upload-request)Request body

No structured schema available for this section.

### [#](#complete-a-direct-media-upload-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

### [#](#complete-a-direct-media-upload-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media/{id}:complete" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{}'
```

Sample payload (application/json)

```json
{}
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.908Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.908Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  }
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media/{id}/replace-uploads`

Requires auth

## [#](#start-replacing-a-media-file)Start replacing a media file

Starts replacing the file of an existing media item with a new one uploaded straight to storage. The media keeps its id, so everything using it follows: Open media steps hand out the new file and page themes show it as their background cover, badge or footer logo from the next visit. Declare the new file's name, MIME type and exact size in bytes, and optionally its sha256\. Then PUT its bytes to upload\_url with the upload\_headers before upload\_expires\_at, and call CompleteReplace with the replacement\_id. Until then the media is unchanged; a replacement not completed within an hour is discarded. The new file must be acceptable to every use rendered from the media's file: a page theme cover, badge or footer logo takes an image of at most 3 MB, an Open media step takes any media. When one refuses it, the replacement is refused with MEDIA\_REPLACE\_NOT\_ALLOWED, whose message names each refusing use and why, and whose metadata lists them in refusals (a JSON array). Media used only by Open media steps may change kind, a PDF for an MP4 video for example. A QR code design keeps its own copy of its logo: it never refuses a replacement, keeps its current logo, and is detached from the media when the replacement completes. A file another media item of the workspace holds is refused with 409 MEDIA\_ALREADY\_EXISTS (metadata existingMediaId and existingFileName). Declaring the media's own file returns unchanged true and no upload\_url: there is nothing to replace. Only the difference in size counts against the workspace's storage allowance. Requires the \`media:write\` scope.

### [#](#start-replacing-a-media-file-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the media item whose file is replaced (UUID)

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#start-replacing-a-media-file-request)Request body

fileName

string

Required

The new file's name. The media takes it once the replacement completes; visitors download the file under it.

mimeType

string

Required

The new file's MIME type: image/png, image/jpeg, image/webp, image/svg+xml, application/pdf or video/mp4\. The uploaded bytes must be this format.

sha256

string

Optional: the new file's SHA-256 digest, 64 hexadecimal characters. When given, a file another media item holds is refused at once with 409 MEDIA\_ALREADY\_EXISTS, the media's own file returns unchanged true, and storage refuses a PUT whose bytes do not match it, so the PUT must carry the x-amz-checksum-sha256 header from upload\_headers.

size

integer (int64)

Required

The new file's exact size in bytes. The PUT must send exactly this many bytes.

### [#](#start-replacing-a-media-file-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

replacementId

string

The replacement's id (UUID), which CompleteReplace takes. Empty when unchanged.

unchanged

boolean

True when the declared sha256 is the media's own file: nothing to upload, nothing changes.

uploadExpiresAt

string (date-time)

When upload\_url stops accepting the file

uploadHeaders

object

Headers the upload must carry, exactly as given: Content-Type, and x-amz-checksum-sha256 when sha256 was declared. The Content-Length must equal the declared size.

uploadMethod

string

The HTTP method to send them with: always PUT. Empty when unchanged.

uploadUrl

string

Where to send the new file's bytes, directly to storage. Short-lived. Empty when unchanged.

### [#](#start-replacing-a-media-file-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media/{id}/replace-uploads" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{"fileName":"menu-autumn.pdf","mimeType":"application/pdf","sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","size":"7340032"}'
```

Sample payload (application/json)

```json
{
  "fileName": "menu-autumn.pdf",
  "mimeType": "application/pdf",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "size": "7340032"
}
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.907Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.907Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  },
  "replacementId": "string",
  "unchanged": false,
  "uploadExpiresAt": "2026-10-25T05:41:07.907Z",
  "uploadHeaders": {},
  "uploadMethod": "string",
  "uploadUrl": "https://example.com"
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media/{id}/replace-uploads/{replacementId}:complete`

Requires auth

## [#](#complete-replacing-a-media-file)Complete replacing a media file

Checks the new file PUT to the replacement's upload\_url like CompleteUpload does (its size, its real format read from its first bytes, its SHA-256 established by the server), checks again that every use rendered from the media accepts it and that it fits the storage allowance, then swaps it in. The media keeps its id and takes the new file's name, MIME type, kind, size and sha256; its old file is deleted. QR code designs that used the media as their logo keep their current logo and are detached from it; they are returned in detached\_references. On any refusal the new file is discarded and the media keeps its current file. A new file identical to the media's own changes nothing and returns unchanged true. Requires the \`media:write\` scope.

### [#](#complete-replacing-a-media-file-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the media item whose file is replaced (UUID)

replacementId

string

Required

path

The replacement's id (UUID), from CreateReplaceUpload

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#complete-replacing-a-media-file-request)Request body

No structured schema available for this section.

### [#](#complete-replacing-a-media-file-response)Response

200

Everything worked as expected.

detachedReferences

array<object>

The uses detached from the media because they keep their own copy of the old file: QR code designs that used it as their logo. They keep showing their current logo.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

unchanged

boolean

True when the new file was the media's own: nothing changed

### [#](#complete-replacing-a-media-file-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media/{id}/replace-uploads/{replacementId}:complete" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{}'
```

Sample payload (application/json)

```json
{}
```

Typical response

```json
{
  "detachedReferences": [
    {
      "linkId": "string",
      "linkName": "string",
      "pageThemeTemplateId": "string",
      "pageThemeTemplateName": "string",
      "qrcodeTemplateId": "string",
      "qrcodeTemplateName": "string",
      "type": "TYPE_UNSPECIFIED",
      "workflowStepId": "string"
    }
  ],
  "media": {
    "createdAt": "2026-10-25T05:41:07.907Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.907Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  },
  "unchanged": false
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media/{id}/replace:import`

Requires auth

## [#](#replace-a-media-file-from-a-url)Replace a media file from a URL

Replaces the file of an existing media item with one fetched server-side, from a public https url or a file the caller attached to their own Assistant conversation, in one call. The same checks as CompleteReplace apply, with the same limits and URL rules as Import: every use rendered from the media must accept the new file (MEDIA\_REPLACE\_NOT\_ALLOWED lists each refusing use and why), a file another media item holds is refused with MEDIA\_ALREADY\_EXISTS, and only the size difference counts against the storage allowance. The media keeps its id; QR code designs using it as a logo keep their current logo and are detached from it. A file identical to the media's own returns unchanged true. Requires the \`media:write\` scope.

### [#](#replace-a-media-file-from-a-url-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the media item whose file is replaced (UUID)

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#replace-a-media-file-from-a-url-request)Request body

assistantAttachmentId

string

The id of a file the caller attached to their own Assistant conversation. Attachments are short-lived and belong to the member who attached them, in that workspace.

fileName

string

The name the media takes. Empty takes the attachment's name, or the last segment of the URL's path, or keeps the media's current name.

url

string

A public https URL the new file is downloaded from, on port 443\. Redirects are followed only to other public https URLs, at most five. The file's kind is read from its bytes.

### [#](#replace-a-media-file-from-a-url-response)Response

200

Everything worked as expected.

detachedReferences

array<object>

The uses detached from the media because they keep their own copy of the old file: QR code designs that used it as their logo. They keep showing their current logo.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

unchanged

boolean

True when the new file was the media's own: nothing changed

### [#](#replace-a-media-file-from-a-url-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media/{id}/replace:import" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{"assistantAttachmentId":"string","fileName":"menu-autumn.pdf","url":"https://example.com/menu-autumn.pdf"}'
```

Sample payload (application/json)

```json
{
  "assistantAttachmentId": "string",
  "fileName": "menu-autumn.pdf",
  "url": "https://example.com/menu-autumn.pdf"
}
```

Typical response

```json
{
  "detachedReferences": [
    {
      "linkId": "string",
      "linkName": "string",
      "pageThemeTemplateId": "string",
      "pageThemeTemplateName": "string",
      "qrcodeTemplateId": "string",
      "qrcodeTemplateName": "string",
      "type": "TYPE_UNSPECIFIED",
      "workflowStepId": "string"
    }
  ],
  "media": {
    "createdAt": "2026-10-25T05:41:07.908Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.908Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  },
  "unchanged": false
}
```

Base URL: `https://api.linkbreakers.com`

POST

`/v1/media/uploads`

Requires auth

## [#](#start-a-direct-media-upload)Start a direct media upload

Reserves a media item for a file uploaded straight to storage, so large files never pass through the API. Declare the file's name, MIME type and exact size in bytes; they are checked against the limit for the file's kind (images up to 10 MB, PDF documents up to 25 MB, MP4 videos up to 50 MB) and against the workspace's storage allowance now, and against the uploaded bytes on completion. Then PUT the file's bytes to upload\_url with the upload\_headers (and a Content-Length equal to size) before upload\_expires\_at, and call CompleteUpload. Until completed the media is PENDING: it is not listed and cannot be used. An upload not completed within an hour is discarded. A workspace holds each file once. Optionally declare sha256, the file's SHA-256 as hex: a file the workspace already holds is then refused here, before any upload, with 409 MEDIA\_ALREADY\_EXISTS, whose metadata names that media in existingMediaId and existingFileName (use it instead), and storage refuses bytes that do not match the hash, so the PUT must send the x-amz-checksum-sha256 header from upload\_headers. Without sha256 the duplicate is caught on completion instead. Requires the \`media:write\` scope.

### [#](#start-a-direct-media-upload-parameters)Parameters

#### header parameters

Idempotency-Key

string

header

Makes retrying this request safe. See components.parameters.IdempotencyKey.

### [#](#start-a-direct-media-upload-request)Request body

fileName

string

Required

The name of the file, shown in the media library and as the file name visitors download

mimeType

string

Required

The file's MIME type: image/png, image/jpeg, image/webp, image/svg+xml, application/pdf or video/mp4\. The uploaded bytes must be this format.

sha256

string

Optional: the file's SHA-256 digest, 64 hexadecimal characters. When given, a file the workspace already holds is refused at once with 409 MEDIA\_ALREADY\_EXISTS (metadata existingMediaId and existingFileName), and storage refuses a PUT whose bytes do not match it, so the PUT must carry the x-amz-checksum-sha256 header from upload\_headers. When omitted, the server hashes the file on completion instead.

size

integer (int64)

Required

The file's exact size in bytes. The PUT must send exactly this many bytes.

uploadedFrom

string (enum)

UploadOrigin is where in the product a media item was uploaded from. It is information only, so pickers can show a section's own uploads first; it never limits where the media can be used. To add a place, add a value here (next number), map it in core, and pass it from the screen that uploads.

##### Allowed values

`UPLOAD_ORIGIN_UNSPECIFIED`

Not set. Uploads that do not say where they come from are recorded as UPLOAD\_ORIGIN\_MEDIA\_LIBRARY.

`UPLOAD_ORIGIN_MEDIA_LIBRARY`

Uploaded from the media library itself

`UPLOAD_ORIGIN_QR_CODE_LOGO`

Uploaded while picking a QR code's logo

`UPLOAD_ORIGIN_BACKGROUND_COVER`

Uploaded while picking a page theme's background cover

`UPLOAD_ORIGIN_BADGE`

Uploaded while picking a page theme's badge

`UPLOAD_ORIGIN_FOOTER_LOGO`

Uploaded while picking a page theme's footer logo

`UPLOAD_ORIGIN_OPEN_MEDIA`

Uploaded while picking the media an Open media step opens

`UPLOAD_ORIGIN_ASSISTANT`

Imported by the Assistant, from a file attached to a conversation or a URL

usage

string (enum)

Deprecated: the value recorded at upload, kept for older clients. It no longer limits anything. Uploads accept images (PNG, JPEG, WebP, SVG) up to 10 MB, PDF documents up to 25 MB and MP4 videos up to 50 MB, whatever the usage. Where media is used is checked when it is attached: a QR code logo, background cover, badge or footer logo must be an image of at most 3 MB; an Open media step takes any media.

##### Allowed values

`USAGE_UNSPECIFIED`

Not set

`USAGE_CENTRAL_QRCODE_IMAGE`

The logo in the center of a QR code

`USAGE_BACKGROUND_COVER`

A page theme's background cover

`USAGE_BADGE`

A page theme's badge image

`USAGE_FOOTER_LOGO`

A page theme's footer logo

`USAGE_OPEN_MEDIA`

Media an Open media workflow step hands to visitors: a PDF menu or brochure, an image or an MP4 video

visibility

string (enum)

The media visibility is not specified

##### Allowed values

`VISIBILITY_UNSPECIFIED`

Media visibility not specified

`VISIBILITY_PUBLIC`

The media visibility is public

`VISIBILITY_PRIVATE`

The media visibility is private

### [#](#start-a-direct-media-upload-response)Response

200

Everything worked as expected.

media

object

A file in the workspace's media library: an image, a PDF document or an MP4 video. A media item only has a kind; where it is used is derived from its references. Any image can be used as a QR code logo, a page theme's background cover, badge or footer logo (up to 3 MB for those), and any media can be opened by an Open media workflow step. Every item counts toward the workspace's media storage allowance (PLAN\_LIMIT\_KEY\_MEDIA\_STORAGE\_MB in allowances).

uploadExpiresAt

string (date-time)

When upload\_url stops accepting the file

uploadHeaders

object

Headers the upload must carry, exactly as given: Content-Type, and x-amz-checksum-sha256 when sha256 was declared. The Content-Length must equal the declared size.

uploadMethod

string

The HTTP method to send them with: always PUT

uploadUrl

string

Where to send the file's bytes, directly to storage. Short-lived.

### [#](#start-a-direct-media-upload-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X POST "https://api.linkbreakers.com/v1/media/uploads" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Idempotency-Key: string" \
  -H "Content-Type: application/json" \
  --data '{"fileName":"menu.pdf","mimeType":"application/pdf","sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","size":"7340032","uploadedFrom":"UPLOAD_ORIGIN_UNSPECIFIED","usage":"USAGE_UNSPECIFIED","visibility":"VISIBILITY_UNSPECIFIED"}'
```

Sample payload (application/json)

```json
{
  "fileName": "menu.pdf",
  "mimeType": "application/pdf",
  "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "size": "7340032",
  "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
  "usage": "USAGE_UNSPECIFIED",
  "visibility": "VISIBILITY_UNSPECIFIED"
}
```

Typical response

```json
{
  "media": {
    "createdAt": "2026-10-25T05:41:07.905Z",
    "fileName": "string",
    "id": "5f1c2d3e-4b5a-6c7d-8e9f-0a1b2c3d4e5f",
    "kind": "KIND_UNSPECIFIED",
    "mediaType": "TYPE_CENTRAL_QRCODE_IMAGE",
    "mimeType": "string",
    "references": [
      {
        "linkId": "string",
        "linkName": "string",
        "pageThemeTemplateId": "string",
        "pageThemeTemplateName": "string",
        "qrcodeTemplateId": "string",
        "qrcodeTemplateName": "string",
        "type": "TYPE_UNSPECIFIED",
        "workflowStepId": "string"
      }
    ],
    "sha256": "string",
    "signedUrl": "https://example.com",
    "size": 0,
    "status": "STATUS_UNSPECIFIED",
    "updatedAt": "2026-10-25T05:41:07.905Z",
    "uploadedBy": "string",
    "uploadedFrom": "UPLOAD_ORIGIN_UNSPECIFIED",
    "usage": "USAGE_UNSPECIFIED",
    "visibility": "VISIBILITY_PRIVATE",
    "workspaceId": "c0d3cafe-5b1e-4d42-a6fd-0c5f5c3962d0"
  },
  "uploadExpiresAt": "2026-10-25T05:41:07.905Z",
  "uploadHeaders": {},
  "uploadMethod": "string",
  "uploadUrl": "https://example.com"
}
```

Base URL: `https://api.linkbreakers.com`

DELETE

`/v1/media/{id}`

Requires auth

## [#](#delete-a-media-file)Delete a media file

Removes a media file from the workspace and frees its storage. This operation cannot be undone. Media still opened by an Open media step, or shown by a page theme as its background cover, badge or footer logo (of a link or of a page theme template), is refused with MEDIA\_IN\_USE, naming what uses it (metadata linkIds and pageThemeTemplateIds): point those at other media or remove it from them first. Deleting an image a QR code design uses as its logo is allowed: the QR code keeps its own copy of the logo, and its link to the media is cleared. Requires the \`media:write\` scope.

### [#](#delete-a-media-file-parameters)Parameters

#### path parameters

id

string

Required

path

The ID of the media file to delete (UUID)

### [#](#delete-a-media-file-response)Response

200

Everything worked as expected.

No structured schema available for this section.

### [#](#delete-a-media-file-error)Error response

400-599

All endpoints may return an unexpected error payload when a request cannot be processed.

error

object

Required

Wrapped error response.

Example request (cURL)

```bash
curl -X DELETE "https://api.linkbreakers.com/v1/media/{id}" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

Typical response

```json
{}
```

Base URL: `https://api.linkbreakers.com`

---

Source: https://linkbreakers.com/help/api/media
