EmberlyEmberly Docs

Files API

Upload, list, update and delete files, including large chunked uploads.

All endpoints need authentication unless noted.

MethodEndpointDescription
POST/api/filesUpload a file
GET/api/filesList your files
PATCH/api/files/{id}Change visibility or password
DELETE/api/files/{id}Delete a file
GET POST DELETE/api/files/{id}/expiryRead, set or remove an expiry date
GET/api/files/{id}/downloadDownload a file
GET/api/files/{id}/ocrText found in an image
GET/api/files/sharedFiles others have shared with you
POST/api/files/chunksStart a large upload

Upload a File

POST /api/files

Send the file as multipart/form-data. This is what ShareX and the other upload tools use.

FieldTypeDescription
filefileRequired. The file to upload.
visibilityPUBLIC or PRIVATEDefaults to PUBLIC. Private files are only visible to you.
passwordstringAsk viewers for this password before showing the file. 8 to 72 characters.
expiresAtISO 8601 dateDelete the file at this time.
domainstringOne of your verified custom domains to use in the returned link.
allowSuggestionstrue or falseLet collaborators suggest edits to text files.
curl https://embrly.ca/api/files \
  -H "Authorization: Bearer ebk_..." \
  -F "[email protected]" \
  -F "visibility=PUBLIC"

Response:

{
  "success": true,
  "data": {
    "id": "clx9k2m...",
    "url": "https://embrly.ca/aB3dE/screenshot.png",
    "name": "screenshot.png",
    "size": 482113,
    "type": "image/png"
  }
}

url is the link to share. If you upload through one of your verified custom domains, or pass domain, the link uses that domain.

Errors:

StatusWhen
400No file, an invalid field, or a blocked file type
403Your email isn't verified, or domain isn't one of your verified domains
413The file is larger than your upload limit, or would take you over your storage quota. Use a chunked upload for big files.

Uploads are checked for malware in the background. A file found to be malicious is removed.


Large Files

Large files upload in parts. The web uploader uses 5 MB parts.

1. Start the upload

POST /api/files/chunks

{
  "filename": "video.mp4",
  "mimeType": "video/mp4",
  "size": 734003200,
  "domain": "files.example.com"
}

domain is optional, as for normal uploads.

Response:

{ "data": { "uploadId": "a1b2c3...", "fileKey": "uploads/..." } }

2. Upload each part

PUT /api/files/chunks/{uploadId}/part/{partNumber}

Send the raw bytes of the part as the request body. Parts are numbered from 1.

curl -X PUT "https://embrly.ca/api/files/chunks/$UPLOAD_ID/part/1" \
  -H "Authorization: Bearer ebk_..." \
  --data-binary @part1.bin

Response:

{ "data": { "etag": "\"9b2cf535f27731c974343645a3985328\"" } }

Keep each part's number and etag for the last step.

Uploading straight to storage

On S3 storage you can upload parts directly to the bucket instead: GET /api/files/chunks/{uploadId}/part/{partNumber} returns a signed url to PUT the part to, and the ETag response header is the part's etag. This is faster for very large files, but the bucket must be reachable from your device.

3. Finish the upload

POST /api/files/chunks/{uploadId}/complete

{
  "parts": [
    { "PartNumber": 1, "ETag": "\"9b2cf535...\"" },
    { "PartNumber": 2, "ETag": "\"4e1f0a7c...\"" }
  ],
  "expiresAt": "2026-12-31T00:00:00Z"
}

expiresAt is optional. The response is the file, without the success/data wrapper:

{
  "id": "clx9k2m...",
  "url": "https://embrly.ca/aB3dE/video.mp4",
  "name": "video.mp4",
  "size": 734003200,
  "type": "video/mp4"
}

Chunked uploads are public. Use PATCH /api/files/{id} afterwards to make one private or add a password.


List Your Files

GET /api/files

QueryDescription
pagePage number, from 1.
limitFiles per page. Defaults to 24.
searchMatch file names.
sortBynewest (default), oldest, largest, smallest, name, most-viewed, least-viewed or most-downloaded.
typesComma-separated file types, as returned by GET /api/files/types.
visibilitypublic, private or hasPassword, comma-separated.
dateFrom, dateToOnly files uploaded in this range (ISO dates).
squadIdList a squad's files instead of your own. You must be a member.

Response:

{
  "success": true,
  "data": [
    {
      "id": "clx9k2m...",
      "name": "screenshot.png",
      "urlPath": "/aB3dE/screenshot.png",
      "mimeType": "image/png",
      "size": 0.46,
      "uploadedAt": "2026-10-24T09:12:44.000Z",
      "visibility": "PUBLIC",
      "views": 12,
      "downloads": 1,
      "hasPassword": false,
      "expiresAt": null
    }
  ],
  "pagination": { "total": 120, "pageCount": 5, "page": 1, "limit": 24 }
}

size is in megabytes. Add urlPath to your instance's address to get the link.


Update a File

PATCH /api/files/{id}

{
  "visibility": "PRIVATE",
  "password": "correct horse"
}

Both fields are optional. Passwords must be 8 to 72 characters; set password to null to remove it. The response is the updated file, without the success/data wrapper:

{
  "id": "clx9k2m...",
  "name": "screenshot.png",
  "urlPath": "/aB3dE/screenshot.png",
  "mimeType": "image/png",
  "size": 0.46,
  "visibility": "PRIVATE",
  "hasPassword": true
}

Delete a File

DELETE /api/files/{id}

Deletes the file and frees the storage. Returns { "success": true }.


Expiry

GET /api/files/{id}/expiry

Returns { "success": true, "data": { "expiresAt": "..." } }, or null if the file doesn't expire.

POST /api/files/{id}/expiry

{
  "expiresAt": "2026-12-31T00:00:00Z",
  "action": "DELETE"
}

action is what happens when the file expires: DELETE (default) or SET_PRIVATE.

DELETE /api/files/{id}/expiry

Removes the expiry.


Download a File

GET /api/files/{id}/download

Downloads the file as an attachment and counts the download. Add ?password=... for password-protected files.

To show a file in a page or app instead, use its link with /raw added, for example https://embrly.ca/aB3dE/screenshot.png/raw.


Text in Images

GET /api/files/{id}/ocr

Returns the text Emberly found in an image, if any. Text is extracted in the background after upload. Add ?password=... for password-protected files.


Shared With You

GET /api/files/shared

Files other people have added you to as a collaborator. Supports page and limit.