Edit on GitHub

Upload API

Everything the uploaders on these pages do goes through two endpoints: POST /api/files to upload a file and POST /api/links to shorten a link. You can call them from any tool that sends HTTP requests.

Upload token

Open Settings → Integrations and copy the Upload token (it starts with fs_). Send it in the Authorization header:

http
Authorization: Bearer fs_...

The upload token only works on POST /api/files and POST /api/links. It cannot list, read or delete anything, so it is safe to put in a script, but keep it private. Regenerate makes a new one and stops the old one; configs and scripts that use it stop working.

Uploading needs the Upload files permission and shortening the Shorten links permission.

Upload a file

POST /api/files with a multipart/form-data body. The file goes in the file field; everything else is optional:

FieldTypeDescription
filefileThe file. Required.
fileNameTypeRandom, UUID or OriginalThe link name. Default: the original name.
expirationnumberMilliseconds until the file is deleted, for example 86400000 for a day. 0 or empty: never.
maxViewsnumberDelete after this many views. 0: unlimited.
passwordstringVisitors must enter it. Up to 48 characters.
compression0 to 100Re-encode images as JPEG at this compression. 0: keep the original.
folderIdstringPut the file in this folder (yours, or a shared folder where you are an editor).

With curl:

sh
curl -H "Authorization: Bearer $FILESHIP_TOKEN" \
  -F "[email protected]" \
  -F "fileNameType=Random" \
  https://files.example.com/api/files

The response is the new file as JSON. The fields you usually need:

FieldDescription
urlThe link to share: the file page (/view/…) when embeds are on or for text files, else the file (/u/…).
directUrlThe file itself, /u/<fileName>.
embedUrlThe file page, /view/<fileName>.
thumbnailUrlThe thumbnail, for images, videos and PDFs.
idThe file's id.
fileNameThe link name.
nameThe display name (the original name).
size{ "raw": "<bytes>", "formatted": "1.2 MB" }.

Links use one of your custom domains when you have some, and follow the link protocol.

A request carries the whole file, however large. Make sure your reverse proxy allows such bodies, or use chunks.

Chunked uploads

For large files, send the file in pieces, the way the dashboard, the Windows app and the browser extension do. Each piece is one POST /api/files request with the same fields as above plus:

FieldDescription
uploadIdAn id you choose for this upload, 1 to 64 letters, digits, _ or -. The same in every piece.
currentChunkThe number of this piece, starting at 1.
totalChunksHow many pieces there are, at most 10,000.
chunkOffsetWhere this piece starts in the file, in bytes: (currentChunk - 1) × chunk size.

Rules:

  • Every piece except the last has the same size, and the last is not larger. Use the server's chunk size: GET /api/settings/public returns fileChunkSize in MB. Pieces larger than it are refused.
  • Pieces can arrive in any order and in parallel. uploadConcurrency in the same response says how many to send at once (1 for FTP storage, otherwise 4).
  • Send the same options (fileNameType, expiration, …) with every piece; the name is chosen with the first one.
  • Pieces before the last answer with an empty response. The request that completes the file returns the file as above.
  • A piece that does not fit the layout fails with Invalid upload chunk. An upload with no new piece for 6 hours is discarded.
  • A piece can be sent again (after a network error, or to resume a paused upload); it replaces the earlier copy. A piece whose request was cut off before its body arrived is not stored. Only the last piece must not be sent again once its whole body went out, because the server may already have completed the file.
  • To cancel, send DELETE /api/files/uploads/<uploadId> with a session (not an upload token). It drops the pieces received so far and answers 204, also when there is nothing to drop.

POST /api/links with a JSON body:

FieldTypeDescription
urlstringThe target, http:// or https://, up to 2048 characters. Required.
codestringThe code after /s/, up to 32 letters, numbers, - or _. Default: random.
passwordstringVisitors must enter it. Up to 48 characters.
maxClicksnumberDelete the link at this many clicks. 0: unlimited.
expirationnumberMilliseconds until the link stops working.
sh
curl -H "Authorization: Bearer $FILESHIP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/a/long/link"}' \
  https://files.example.com/api/links

The response is the link as JSON, with the short address in shortUrl.

Errors

Errors come back as JSON with a message in the language of the request's Accept-Language header, and a status code:

StatusMeaning
400A field is invalid (Some fields are invalid), the file is missing, or Storage limit reached (then data.quotaExceeded is true).
401The token is missing or wrong (You must be logged in to perform this action).
403The account lacks the permission (You do not have permission to perform this action).
409The link name or code is taken (A file with that name already exists, That short link is already taken).
413Your proxy refused the body; see Upload problems.

Don't compare the message text in your code; it is translated. Check the status and the data flags. See the error index for every message.

Other uploaders

Ready-made configs: ShareX, macOS, Linux, Flameshot, iOS Shortcuts, Android and curl.