Opal has two upload routes. POST /items/upload creates a standalone file item on a workspace. POST /media/upload uploads an image, video, audio file, or other file and returns a ready-to-use block, and can insert it into a page. Both send multipart form data with the file in a field named file, and both follow your plan’s file size and storage limits.

Upload a Standalone File Item

POST /api/v1/items/upload
FieldRequiredNotes
fileYesThe file to upload. The field must be named file.
workspaceYesTarget workspace submission ID. It must be yours.
xPosition, yPositionNoOptional placement.
curl -X POST https://app.opalrecall.com/api/v1/items/upload \
  -H "Authorization: Bearer opal_live_xxx" \
  -F "file=@report.pdf" \
  -F "workspace=WORKSPACE_ID"

Creates a new file item and returns it with 201. The item gets file subtype classes such as type-file file-type-pdf. Images also store their dimensions for resize behavior. Text files up to 1 MB keep their text inside the item. Larger ones stay downloadable files.

A Markdown (.md) upload becomes a document item when it converts within the content limit. Its title is the first # heading, or the file name, and editorContent keeps the uploaded file’s URL and name as sourceFileUrl and sourceFileName.

Opal checks, in order: the plan’s max file size (413), 400 without a file or workspace, storage (413), the item limit (403), and the workspace (403 if it is not yours, 404 if it does not exist).

Do not hand-build standalone file items when this route is available. The upload route sets the file subtype classes that the grid needs.

Get a Download URL

GET /api/v1/items/:id/download
curl https://app.opalrecall.com/api/v1/items/ITEM_ID/download \
  -H "Authorization: Bearer opal_live_xxx"
{
  "data": {
    "url": "https://..."
  }
}

The URL is the item’s file (or, for a document, the first stored image, video, audio, or file block). Links to Opal’s storage come back with the current read token. Links to other sites come back as saved. This needs ownership, a share with canView, or canView on a binder or fence the item is in. It returns 404 No file URL found when the item has no file.

Upload Media for Embedding

POST /api/v1/media/upload
FieldRequiredNotes
fileYesImage, video, audio, or any other file. The field must be named file.
captionNoCaption for image, video, and audio blocks.
itemIdNoSubmission or item_ ID. If given, the block is inserted into that item.
positionNostart or end. Defaults to end when inserting.
curl -X POST https://app.opalrecall.com/api/v1/media/upload \
  -H "Authorization: Bearer opal_live_xxx" \
  -F "file=@cover.png" \
  -F "itemId=ITEM_ID" \
  -F "position=end"

Response (201):

{
  "data": {
    "url": "https://...blob.core.windows.net/...",
    "blockType": "image",
    "block": {
      "id": "media_ab12cd34",
      "type": "image",
      "props": {
        "url": "...",
        "caption": "",
        "previewWidth": 800
      },
      "children": []
    },
    "dimensions": {
      "width": 1024,
      "height": 768
    },
    "fileName": "cover.png",
    "fileSize": 204800,
    "mimeType": "image/png",
    "embedded": true
  }
}

The file extension decides the block type:

Block typeExtensions
imagejpg, jpeg, png, gif, webp, svg, bmp, tiff, heic, heif, ico
videomp4, mov, avi, mkv, webm, m4v
audiomp3, wav, ogg, m4a, flac, aac, wma
fileAnything else

SVGs are sanitized, and risky file types are stored to download rather than open. Inserting into an item needs edit access to it (owner, a canEdit share, or canEdit on a binder or fence it is in). Without it the route returns 403 before anything is uploaded. The block and an empty paragraph after it are added at the start or end. If the item’s content would go over 2 MB, the route returns 413 and uploads nothing.

Which Route to Use

  • To create a standalone file item in Opal, use POST /items/upload.
  • To put an image, video, audio file, or file inside a document, use POST /media/upload.

Size and Storage Limits

Plan file-size and storage limits apply to both routes. Check plan.limits.fileSizeBytes before each upload, and compare the total against your remaining storage, using GET /account. See Plan, Limits, and Usage in the Opal API: GET /account. For the per-plan numbers, see File Size and Storage Limits by Plan. Over-limit responses are listed in Errors, Rate Limits, and Plan Limits in the Opal API.

Next Steps

FAQ

What is the difference between items/upload and media/upload?

POST /items/upload creates a new standalone file item on a workspace. POST /media/upload returns a ready-made image, video, audio, or file block, and can insert it into an item you can edit.

What happens if my file is too big?

The route returns 413 with limit and readable fields. The limit is your plan’s max file size. See Errors, Rate Limits, and Plan Limits in the Opal API.

What happens to a Markdown file I upload?

A .md upload becomes a document item when it converts within the content limit. Its title is the first # heading, or the file name.

How do I download a file with the API?

Call GET /items/:id/download. It returns a URL for the item’s file. You need ownership or a share with canView.