List, search, update and delete your own files, folders, videos and labels from your server, for example to clean up files when a record in your database is deleted. Every request is limited to your app, so one app can never see or change another's files.
403 private_key_requiredFilter by label, type prefix, name, hash, metadata and creation date, sort, and page with the cursor in
nextCursor// one page, newest first. Needs the private key.
const page = await fileboy.listFiles({
mime: "image/",
metadata: { orderId: "42" },
limit: 25,
})
page.data.forEach(file => console.log(file.id, file.name, file.labels))
// the next page
if (page.nextCursor) {
await fileboy.listFiles({ mime: "image/", metadata: { orderId: "42" }, cursor: page.nextCursor })
}# one page, newest first. Needs the private key.
page = fileboy.list_files(mime: "image/", metadata: { orderId: "42" }, limit: 25)
page.items.each { |file| puts "#{file.id} #{file.name} #{file.labels}" }
# or walk every page
fileboy.each_file(mime: "image/") { |file| puts file.name }# one page, newest first. Needs the private key.
page = client.list_files(mime="image/", metadata={"orderId": "42"}, limit=25)
for file in page.items:
print(file.id, file.name, file.labels)
# or walk every page
for file in client.iter_files(mime="image/"):
print(file.name)// one page, newest first. Needs the private key.
$page = $fileboy->listFiles(['mime' => 'image/', 'metadata' => ['orderId' => '42'], 'limit' => 25]);
foreach ($page->data as $file) {
echo $file->id, ' ', $file->name, "
";
}
// or walk every page
foreach ($fileboy->eachFile(['mime' => 'image/']) as $file) {
echo $file->name, "
";
}curl -G https://api.fileboy.io/files \
-H "Authorization: token YOUR_SIGNED_TOKEN" \
--data-urlencode "mime=image/" \
--data-urlencode "metadata[orderId]=42" \
--data-urlencode "limit=25"Only the fields you send change. Metadata is merged: keys you send are set, a null value removes a key, other keys stay. Ask for
replaceMetadatasharePage: true// metadata is merged: a null value removes a key
const updated = await fileboy.updateFileData(file.id, {
name: "invoice-1042-final.pdf",
metadata: { status: "paid", draft: null },
labels: { add: ["latest-invoice"] },
})# metadata is merged: nil removes a key
updated = fileboy.update_file(
file.id,
name: "invoice-1042-final.pdf",
metadata: { status: "paid", draft: nil },
labels: { add: ["latest-invoice"] }
)# metadata is merged: None removes a key
updated = client.update_file(
file.id,
name="invoice-1042-final.pdf",
metadata={"status": "paid", "draft": None},
add_labels=["latest-invoice"],
)// metadata is merged: null removes a key
$updated = $fileboy->updateFile($file->id, [
'name' => 'invoice-1042-final.pdf',
'metadata' => ['status' => 'paid', 'draft' => null],
'labels' => ['add' => ['latest-invoice']],
]);curl -X PATCH https://api.fileboy.io/files/FILE_ID \
-H "Authorization: token YOUR_SIGNED_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"invoice-1042-final.pdf","metadata":{"status":"paid","draft":null},"labels":{"add":["latest-invoice"]}}'Deleting removes the stored data, including cached resized copies of an image, and sends a
file.deletedfile_not_foundimport { notFoundError } from "@cd2/fileboy-node"
try {
await fileboy.destroyFile(file.id)
} catch (e) {
if (!notFoundError.is(e)) throw e // already gone is fine
}begin
fileboy.delete_file(file.id)
rescue Fileboy::NotFoundError
# already gone is fine
endtry:
client.delete_file(file.id)
except fileboy.NotFoundError:
pass # already gone is finetry {
$fileboy->deleteFile($file->id);
} catch (\Fileboy\Exception\NotFoundException $e) {
// already gone is fine
}curl -X DELETE https://api.fileboy.io/files/FILE_ID \
-H "Authorization: token YOUR_SIGNED_TOKEN"
# 204 when deleted, 404 when there is no such file// up to 100 ids. Unknown ids are reported, not thrown.
const { deleted, notFound, failed } = await fileboy.destroyFiles(ids)# up to 100 ids. Unknown ids are reported, not raised.
result = fileboy.delete_files(ids)
result.deleted # ids that were deleted
result.not_found # unknown or already deleted
result.failed # still there because storage was unreachable: send again# up to 100 ids. Unknown ids are reported, not raised.
result = client.delete_files(ids)
result.deleted # ids that were deleted
result.not_found # unknown or already deleted
result.failed # still there because storage was unreachable: send again// up to 100 ids. Unknown ids are reported, not thrown.
$result = $fileboy->deleteFiles($ids);
$result->deleted; // ids that were deleted
$result->notFound; // unknown or already deleted
$result->failed; // still there because storage was unreachable: send againcurl -X POST https://api.fileboy.io/files/delete \
-H "Authorization: token YOUR_SIGNED_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids":["FILE_ID_1","FILE_ID_2"]}'failedGET /files/:id/exif?personal=false// needs the private key: the answer can hold the GPS position and serial numbers
const exif = await fileboy.getFileExif(file.id)
exif.fields.model // "iPhone 15 Pro"
exif.fields.shutterSpeed // "1/60"
exif.fields.dateTaken // "2026-02-19T14:22:37.146-08:00"
exif.fields.gps // { latitude: 51.5007, longitude: -0.1246, altitude: 13.21 } or null
// without GPS, place names, serial numbers or the owner, to show your own users
const shareable = await fileboy.getFileExif(file.id, { personal: false })# needs the private key: the answer can hold the GPS position and serial numbers
exif = fileboy.fetch_file_exif(file.id)
exif.fields.model # => "iPhone 15 Pro"
exif.fields.date_taken # => "2026-02-19T14:22:37.146-08:00"
exif.fields.gps&.latitude # => 51.5007
shareable = fileboy.fetch_file_exif(file.id, personal: false)# needs the private key: the answer can hold the GPS position and serial numbers
exif = client.get_file_exif(file.id)
exif.fields.model # "iPhone 15 Pro"
exif.fields.date_taken # "2026-02-19T14:22:37.146-08:00"
exif.fields.gps # ExifGps(latitude=51.5007, longitude=-0.1246, altitude=13.21) or None
shareable = client.get_file_exif(file.id, personal=False)// needs the private key: the answer can hold the GPS position and serial numbers
$exif = $fileboy->getFileExif($file->id);
echo $exif->fields->model; // iPhone 15 Pro
echo $exif->fields->dateTaken; // 2026-02-19T14:22:37.146-08:00
$exif->fields->gps?->latitude; // 51.5007, or null
$shareable = $fileboy->getFileExif($file->id, personal: false);curl https://api.fileboy.io/files/FILE_ID/exif \
-H "Authorization: token YOUR_SIGNED_TOKEN"
# without the personal data
curl "https://api.fileboy.io/files/FILE_ID/exif?personal=false" \
-H "Authorization: token YOUR_SIGNED_TOKEN"Create folders (one by name, or a whole path at once), list them, rename and move them, and move up to 100 files at a time with
POST /files/movefolderIdfolderPathGET /files// mkdir -p: makes any folder on the path that is missing
const shoes = await fileboy.createFolder({ path: "/Products/Shoes" })
await fileboy.uploadFileFromPath("./red.png", { folderPath: "/Products/Shoes" })
const page = await fileboy.listFiles({ folderId: shoes.id }) // or { folderPath: "/Products", recursive: true }
await fileboy.moveFiles([file.id], { folderId: shoes.id }) // { folderId: null } is the top level
await fileboy.updateFolder(shoes.id, { name: "Trainers" }) // links to the files don't change
await fileboy.destroyFolder(shoes.id, { contents: "moveToParent" })shoes = fileboy.create_folder(path: "/Products/Shoes")
fileboy.upload_file("red.png", folder_path: "/Products/Shoes")
page = fileboy.list_files(folder_id: shoes.id)
fileboy.move_files([file.id], folder_id: shoes.id)
fileboy.update_folder(shoes.id, name: "Trainers")
fileboy.delete_folder(shoes.id, contents: "moveToParent")shoes = client.create_folder(path="/Products/Shoes")
client.upload_file("red.png", folder_path="/Products/Shoes")
page = client.list_files(folder_id=shoes.id)
client.move_files([file.id], shoes.id)
client.update_folder(shoes.id, name="Trainers")
client.delete_folder(shoes.id, contents="moveToParent")$shoes = $fileboy->createFolder(path: '/Products/Shoes');
$fileboy->uploadFile('red.png', folderPath: '/Products/Shoes');
$page = $fileboy->listFiles(['folderId' => $shoes->id]);
$fileboy->moveFiles([$file->id], $shoes->id);
$fileboy->updateFolder($shoes->id, ['name' => 'Trainers']);
$fileboy->deleteFolder($shoes->id, 'moveToParent');curl -X POST https://api.fileboy.io/folders \
-H "Authorization: token YOUR_SIGNED_TOKEN" -H "Content-Type: application/json" \
-d '{"path":"/Products/Shoes"}'
curl -G https://api.fileboy.io/files -H "Authorization: token YOUR_SIGNED_TOKEN" \
--data-urlencode folderPath=/Products/ShoesDeleting a video removes the original, the posters, the transcripts and every rendition, and sends
video.deletedconst { data: videos } = await fileboy.listVideos({ status: "ready", limit: 20 })
await fileboy.updateVideo(videos[0].id, { name: "Launch day" })
await fileboy.destroyVideo(videos[0].id) // original, renditions, posters and transcriptspage = fileboy.list_videos(status: "ready", limit: 20)
fileboy.update_video(page.items.first.id, name: "Launch day")
fileboy.delete_video(page.items.first.id) # original, renditions, posters and transcriptspage = client.list_videos(status="ready", limit=20)
client.update_video(page.items[0].id, name="Launch day")
client.delete_video(page.items[0].id) # original, renditions, posters and transcripts$page = $fileboy->listVideos(['status' => 'ready', 'limit' => 20]);
$fileboy->updateVideo($page->data[0]->id, 'Launch day');
$fileboy->deleteVideo($page->data[0]->id); // original, renditions, posters and transcriptscurl -G https://api.fileboy.io/videos -H "Authorization: token YOUR_SIGNED_TOKEN" -d status=ready
curl -X DELETE https://api.fileboy.io/videos/VIDEO_ID -H "Authorization: token YOUR_SIGNED_TOKEN"const labels = await fileboy.listLabels()
await fileboy.createLabel("hero", { fileId: file.id })
await fileboy.destroyLabel("hero") // the file is keptlabels = fileboy.list_labels
fileboy.create_label("hero", file_id: file.id)
fileboy.delete_label("hero") # the file is keptlabels = client.list_labels()
client.create_label("hero", file_id=file.id)
client.delete_label("hero") # the file is kept$labels = $fileboy->listLabels();
$fileboy->createLabel('hero', $file->id);
$fileboy->deleteLabel('hero'); // the file is keptcurl -X POST https://api.fileboy.io/labels \
-H "Authorization: token YOUR_SIGNED_TOKEN" -H "Content-Type: application/json" \
-d '{"name":"hero","fileId":"FILE_ID"}'How many files and videos you have and how many bytes they store, next to your plan's limits. Data transfer is not reported.
const usage = await fileboy.getUsage()
console.log(usage.files, usage.storageBytes, usage.limits.storageBytes)usage = fileboy.fetch_usage
puts "#{usage.files} files, #{usage.storage_bytes} bytes"usage = client.get_usage()
print(usage.files, usage.storage_bytes, usage.limits.storage_bytes)$usage = $fileboy->getUsage();
echo $usage->files, ' files, ', $usage->storageBytes, " bytes
";curl https://api.fileboy.io/usage -H "Authorization: token YOUR_SIGNED_TOKEN"To be told before you reach a limit instead of polling, use usage alerts: an email, a dashboard banner and a
usage.threshold_reached/usage/alertsWhat your storage is made of: images, other files, video originals, renditions, posters, captions and the cached copies Fileboy makes of resized images. Each stored file counts once, under one kind, so the kinds add up to the same
storageBytes/usageconst storage = await fileboy.getStorageUsage({ days: 90 })
console.log(storage.kinds.videoRenditions.bytes, storage.largestFiles[0]?.name)
for (const day of storage.history) console.log(day.date, day.storageBytes)storage = fileboy.fetch_storage_usage(days: 90)
puts storage.kinds["videoRenditions"].bytes, storage.largest_files.first&.name
storage.history.each { |day| puts "#{day.date} #{day.storage_bytes}" }storage = client.get_storage_usage(days=90)
print(storage.kinds["videoRenditions"].bytes, storage.largest_files[0].name if storage.largest_files else None)
for day in storage.history:
print(day.date, day.storage_bytes)$storage = $fileboy->getStorageUsage(['days' => 90]);
echo $storage->kinds['videoRenditions']['bytes'], "\n";
foreach ($storage->history as $day) { echo $day['date'], ' ', $day['storageBytes'], "\n"; }curl 'https://api.fileboy.io/usage/storage?days=90' -H "Authorization: token YOUR_SIGNED_TOKEN"Your app's videos, newest first by default. Needs a token signed with your private key.
1https://api.fileboy.io/videos
Query Params
limit number, optional, default is 50
1 to 100.
cursor string, optional
The previous nextCursor.
sort createdAt | name, optional
What to sort by.
order asc | desc, optional
Sort direction.
name string, optional
Name contains this text.
status pending | processing | ready | failed, optional
Only videos in this state.
tags string, optional
Only videos with every one of these tags, comma-separated (tags=launch,2026) or repeated. Up to 20.
metadata[key] string, optional
Only videos whose metadata has this value for the key. Repeat for more pairs (up to 20), or send metadata={"orderId":"42"}.
createdBefore string, optional
ISO 8601.
createdAfter string, optional
ISO 8601.
Example
1curl -G 'https://api.fileboy.io/videos' -H 'Authorization: token 0000000....' --data-urlencode 'status=ready' --data-urlencode 'tags=launch' --data-urlencode 'metadata[orderId]=42'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22{ "data": [{ "id": "9b1c4d1e-5c1e-4b8e-9d57-3f0a4f1a7c10", "name": "launch.mp4", "createdAt": "2026-01-02T03:04:05Z", "status": "ready", "statusMessage": "", "duration": 12.5, "width": 1280, "height": 720, "playCount": 3, "lastPlayedAt": null, "description": "Our launch, in two minutes.", "tags": ["launch", "2026"], "metadata": { "orderId": "42" }, "urls": { "manifest": "https://api.fileboy.io/videos/9b1c.../manifest", "hls": "https://api.fileboy.io/videos/9b1c.../manifest?type=hls", "dash": "https://api.fileboy.io/videos/9b1c.../manifest?type=dash", "poster": "https://api.fileboy.io/videos/9b1c.../poster" }, "playerBranding": {} }], "nextCursor": null }
Changes the video's name, description, tags, metadata or its own player branding. Only the fields you send change, and a request that would go over a limit changes nothing. Needs your private key.
1https://api.fileboy.io/videos/:id
URL Params
id string
The video's id.
Body
name string, optional
The new name, 1 to 1024 characters.
description string | null, optional
Plain text up to 5000 characters, trimmed, line breaks kept. Public. "" or null removes it.
tags string[] | null | { add, remove }, optional
A list replaces the tags, null removes them all, { add: [...], remove: [...] } changes some.
metadata object, optional
String values to set, merged into the existing metadata. A null value removes a key.
replaceMetadata boolean, optional
Make metadata the complete new metadata.
playerBranding object | null, optional
This video's player branding, on top of the app's (see Player branding below). Each field it sets replaces the app's; controls merge one by one. null makes the video follow the app again.
Example
1curl -X PATCH 'https://api.fileboy.io/videos/9b1c4d1e-5c1e-4b8e-9d57-3f0a4f1a7c10' -H 'Authorization: token 0000000....' -H 'Content-Type: application/json' --data '{"description":"Our launch, in two minutes.","tags":{"add":["launch"]},"metadata":{"orderId":"42"}}'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22{ "data": { "id": "9b1c4d1e-5c1e-4b8e-9d57-3f0a4f1a7c10", "name": "launch.mp4", "createdAt": "2026-01-02T03:04:05Z", "status": "ready", "statusMessage": "", "duration": 12.5, "width": 1280, "height": 720, "playCount": 3, "lastPlayedAt": null, "description": "Our launch, in two minutes.", "tags": ["launch", "2026"], "metadata": { "orderId": "42" }, "urls": { "manifest": "https://api.fileboy.io/videos/9b1c.../manifest", "hls": "https://api.fileboy.io/videos/9b1c.../manifest?type=hls", "dash": "https://api.fileboy.io/videos/9b1c.../manifest?type=dash", "poster": "https://api.fileboy.io/videos/9b1c.../poster" }, "playerBranding": {} } }
Removes the original, posters, transcripts and renditions from storage, then the video, and sends video.deleted. 404 if there is no such video. If storage cannot be reached the answer is 500: the video is still listed with whatever was not yet removed, and you can repeat the request to finish. Needs your private key.
1https://api.fileboy.io/videos/:id
URL Params
id string
The video's id.
Example
1curl -X DELETE 'https://api.fileboy.io/videos/9b1c4d1e-5c1e-4b8e-9d57-3f0a4f1a7c10' -H 'Authorization: token 0000000....'
1// 204 No Content
The player branding every video of the app starts with: colours, a logo, which controls show, and autoplay, muted and loop. Players read the result for one video from GET /videos/:id/player-config (see Play a video). Send playerBranding alone or with requireSignedReads and stripLocationOnUpload; null clears it. A bad value is a 400 validation_error that lists every problem, and the logo must be an image in this app. GET /app/settings returns it too. Needs your private key.
1https://api.fileboy.io/app/settings
Body
playerBranding.accentColor, controlsColor, backgroundColor string, optional
Hex colours (#rgb or #rrggbb): the progress bar and hovered buttons, icons and text, and the area around the video.
playerBranding.logo object | null, optional
fileId (an image in this app), position (top-left, top-right, bottom-left or bottom-right; top-right by default), link (http or https, opens in a new tab) and alt (the name screen readers read, up to 200 characters).
playerBranding.controls object, optional
true or false for play, seek, volume, time, captions, speed, quality, pip, fullscreen, download and title. Every control shows by default except download, which offers the original file.
playerBranding.autoplay, muted, loop boolean, optional
Playback defaults. Autoplay always starts muted.
Example
1 2 3 4 5 6 7curl -X PATCH 'https://api.fileboy.io/app/settings' -H 'Authorization: token 0000000....' -H 'Content-Type: application/json' --data '{ "playerBranding": { "accentColor": "#ff3e6c", "logo": { "fileId": "9d44134a-0fac-4c6f-86bc-18780e8e0a45", "position": "top-right", "link": "https://example.com", "alt": "Acme" }, "controls": { "pip": false, "download": true } } }'
1 2 3 4 5 6 7 8 9 10 11{ "data": { "requireSignedReads": false, "stripLocationOnUpload": false, "playerBranding": { "accentColor": "#ff3e6c", "logo": { "fileId": "9d44134a-0fac-4c6f-86bc-18780e8e0a45", "position": "top-right", "link": "https://example.com", "alt": "Acme" }, "controls": { "pip": false, "download": true } } } }
Your app's labels. A label is a name that points at one file, so PUBLIC_KEY+LABEL works anywhere a file id does. Needs your private key.
1https://api.fileboy.io/labels
Example
1curl 'https://api.fileboy.io/labels' -H 'Authorization: token 0000000....'
1{ "data": [{ "id": "…", "name": "logo", "createdAt": "2026-01-02T03:04:05Z", "fileId": "9d44134a-0fac-4c6f-86bc-18780e8e0a45" }] }
Label names are 1 to 100 characters with no spaces and none of - + / \ ? # % &. Answers 409 label_taken if the name exists. Needs your private key.
1https://api.fileboy.io/labels
Body
name string
The label.
fileId string, optional
A file of yours to point it at.
Example
1curl -X POST 'https://api.fileboy.io/labels' -H 'Authorization: token 0000000....' -H 'Content-Type: application/json' --data '{"name":"hero","fileId":"9d44134a-0fac-4c6f-86bc-18780e8e0a45"}'
1{ "data": { "id": "…", "name": "hero", "createdAt": "2026-01-02T03:04:05Z", "fileId": "9d44134a-0fac-4c6f-86bc-18780e8e0a45" } }
Removes the label, not the file it points at. 404 if there is no such label. Needs your private key.
1https://api.fileboy.io/labels/:name
URL Params
name string
The label's name.
Example
1curl -X DELETE 'https://api.fileboy.io/labels/hero' -H 'Authorization: token 0000000....'
1// 204 No Content
Files and videos you have, and everything stored (files, resized copies, video renditions, posters). limits are the ones set on your app (from your plan, or an agreement); null means none is set on the app, not unlimited. Needs your private key.
1https://api.fileboy.io/usage
Example
1curl 'https://api.fileboy.io/usage' -H 'Authorization: token 0000000....'
1 2 3 4 5 6 7 8{ "data": { "files": 120, "videos": 4, "storageBytes": 734003200, "limits": { "files": 1000, "videos": null, "storageBytes": 5368709120 } } }
Stored bytes by kind, your biggest files and videos, and one total a day. storageBytes is the same as GET /usage, and the kinds add up to it. Daily totals are recorded just after midnight UTC and kept for 400 days; days before tracking started are missing, never filled in. Needs your private key.
1https://api.fileboy.io/usage/storage
Query Params
days number, optional
How many days of daily totals to return, 1 to 365. Defaults to 30.
top number, optional
How many of the biggest files and videos to list, 1 to 50. Defaults to 10.
Response
kinds object
count and bytes for each of images, files (every other upload), videoOriginals, videoRenditions, videoPosters, videoCaptions, imageTransforms (cached resized and converted copies) and otherGenerated. Every kind is present.
largestFiles File[]
Your biggest files, biggest first, as GET /files returns them. Video parts and generated copies are not listed.
largestVideos object[]
The videos that store the most: storageBytes (all parts together), originalBytes, renditionBytes, posterBytes and captionBytes.
history object[]
date (a UTC day), storageBytes and bytes by kind, oldest first.
Example
1curl 'https://api.fileboy.io/usage/storage?days=30&top=5' -H 'Authorization: token 0000000....'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22{ "data": { "storageBytes": 734003200, "limits": { "storageBytes": 5368709120 }, "kinds": { "images": { "count": 96, "bytes": 210763776 }, "files": { "count": 24, "bytes": 31457280 }, "videoOriginals": { "count": 4, "bytes": 314572800 }, "videoRenditions": { "count": 16, "bytes": 157286400 }, "videoPosters": { "count": 4, "bytes": 1048576 }, "videoCaptions": { "count": 2, "bytes": 20480 }, "imageTransforms": { "count": 310, "bytes": 18853888 }, "otherGenerated": { "count": 0, "bytes": 0 } }, "largestFiles": [{ "id": "2a860257-…", "name": "brochure.pdf", "fileSize": 20971520, … }], "largestVideos": [{ "id": "9b1c4d1e-…", "name": "launch.mp4", "status": "ready", "storageBytes": 134217728, "originalBytes": 83886080, "renditionBytes": 50069504, "posterBytes": 262144, "captionBytes": 0 }], "history": [{ "date": "2026-11-13", "storageBytes": 731906048, "kinds": { "images": 208666624, … } }] } }
The app's usage alert settings, the current month (UTC) and the alerts recorded in it, newest first. See the usage alerts docs for when alerts fire. Needs your private key.
1https://api.fileboy.io/usage/alerts
Example
1curl 'https://api.fileboy.io/usage/alerts' -H 'Authorization: token 0000000....'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16{ "data": { "settings": { "enabled": true, "thresholds": [80, 100], "metrics": { "files": true, "videos": true, "storage": true }, "emailMembers": true, "recipients": [], "webhook": true }, "period": { "key": "2026-11", "start": "2026-11-01T00:00:00Z", "end": "2026-12-01T00:00:00Z" }, "alerts": [ { "id": "8d2b…", "metric": "files", "threshold": 80, "used": 812, "limit": 1000, "notified": true, "email": "sent", "createdAt": "2026-11-14T10:05:00Z" } ] } }
Only the fields you send change; metrics only changes the limits it names. Answers with the same body as the GET. Needs your private key.
1https://api.fileboy.io/usage/alerts
Body
enabled boolean, optional
Off stops every alert.
thresholds number[], optional
1 to 5 whole percentages from 1 to 100. Sorted, duplicates removed.
metrics object, optional
files, videos and storage, each true or false.
emailMembers boolean, optional
Email everyone on the app.
recipients string[], optional
Up to 10 more email addresses. Replaces the list.
webhook boolean, optional
Send usage.threshold_reached webhooks.
Example
1curl -X PATCH 'https://api.fileboy.io/usage/alerts' -H 'Authorization: token 0000000....' -H 'Content-Type: application/json' -d '{ "thresholds": [50, 80, 90, 100] }'
1// 200, the same body as GET /usage/alerts
A link to the file, or one image transform of it, that stops working at expiresAt and can be revoked early. Give expiresAt or expiresIn, a minute to 365 days away. 100 active links per file (409 too_many_links). It works whatever the file's read permission, but a public file's own URL keeps working. See Expiring links in Delivery. Needs your private key.
1https://api.fileboy.io/files/:id/links
URL Params
id string
The file's id or PUBLIC_KEY+LABEL.
Body
expiresIn number, optional
Seconds from now. Give this or expiresAt.
expiresAt string, optional
ISO 8601 time with a time zone.
transform string, optional
An image transform, checked now (400 invalid_transform).
download boolean, optional
Send as a download.
filename string, optional
Save under this name.
note string, optional
For you, up to 200 characters.
Example
1curl -X POST 'https://api.fileboy.io/files/9d44134a-0fac-4c6f-86bc-18780e8e0a45/links' -H 'Authorization: token 0000000....' -H 'Content-Type: application/json' --data '{"expiresIn":604800,"note":"for the auditors"}'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18{ "data": { "id": "5f0c2a8e-3b1d-4c7a-9e2f-6a1b8c9d0e1f", "fileId": "9d44134a-0fac-4c6f-86bc-18780e8e0a45", "url": "https://api.fileboy.io/links/q7Hc2mX9pLwR4tYvB8nK1sDf", "status": "active", "expiresAt": "2026-11-21T12:00:00Z", "revokedAt": null, "transform": "", "download": false, "filename": "", "note": "for the auditors", "createdVia": "api", "createdAt": "2026-11-14T12:00:00Z", "lastUsedAt": null, "useCount": 0 } }
Newest first, every status unless status=active, with useCount and lastUsedAt. Needs your private key.
1https://api.fileboy.io/files/:id/links
URL Params
id string
The file's id or PUBLIC_KEY+LABEL.
Query Params
status active | all, optional, default is all
active leaves out expired and revoked links.
limit number, optional, default is 50
1 to 100.
cursor string, optional
The previous nextCursor.
Example
1curl 'https://api.fileboy.io/files/9d44134a-0fac-4c6f-86bc-18780e8e0a45/links?status=active' -H 'Authorization: token 0000000....'
1{ "data": [{ "id": "…", "status": "active", … }], "nextCursor": null }
The link answers 410 link_revoked from now on. Safe to repeat. Answers with the link. Needs your private key.
1https://api.fileboy.io/files/:id/links/:linkId
URL Params
id string
The file's id or PUBLIC_KEY+LABEL.
linkId string
The link's id.
Example
1curl -X DELETE 'https://api.fileboy.io/files/9d44134a-0fac-4c6f-86bc-18780e8e0a45/links/5f0c2a8e-3b1d-4c7a-9e2f-6a1b8c9d0e1f' -H 'Authorization: token 0000000....'
1{ "data": { "id": "…", "status": "revoked", "revokedAt": "…", … } }
The dominant colour, main colours with their share of the image, named swatches and a readable text colour for each. Worked out at upload, or on the first request for older images. 422 unsupported_image for files that are not JPEG, PNG, WebP, BMP or TIFF. Needs your private key; the palette transform serves the same palette on image URLs.
1https://api.fileboy.io/files/:id/palette
URL Params
id string
The file's id, or PUBLIC_KEY+label.
Query Params
colors number, optional, default is 6
How many main colours to list, 0 to 16.
Example
1curl 'https://api.fileboy.io/files/FILE_ID/palette?colors=2' -H 'Authorization: token 0000000....'
1 2 3 4 5 6 7 8 9 10 11 12{ "data": { "version": 1, "dominant": { "hex": "#3d5a73", "rgb": [61, 90, 115], "share": 0.4213, "text": "#ffffff", "contrast": 7.22 }, "colors": [ { "hex": "#3d5a73", "rgb": [61, 90, 115], "share": 0.4213, "text": "#ffffff", "contrast": 7.22 }, { "hex": "#e8d9c4", "rgb": [232, 217, 196], "share": 0.2876, "text": "#000000", "contrast": 15.15 } ], "swatches": { "vibrant": { "hex": "#c2452d", ... }, "darkVibrant": null, "lightVibrant": { "hex": "#e8d9c4", ... }, "muted": { "hex": "#3d5a73", ... }, "darkMuted": null, "lightMuted": null }, "transparentShare": 0 } }
Errors are JSON,
{ "error": "file_not_found", "message": "…" }