Files API
Signed uploads into the project's object store, owner-scoped downloads and soft deletes.
On this page
Base URL: your app's origin ($APP_ORIGIN): the published host, a custom domain, or the platform origin for the builder preview. Errors answer { ok: false, error: { code, message } } unless noted. Add x-appbricx-env: dev or prod to pick the database explicitly; otherwise the host decides (preview means dev, a published host means prod).
Authentication
- App key + signed-in user
- A project key or preview token and a signed-in app session (header or cookie). Signed-out callers get 401.
Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Endpoints
Sign an upload
POST/__appbricx/files/sign
Check type and size and mint a signed file id plus the URL to post the file to.
- Auth
- App key + signed-in user:
Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Body
| Name | Type | Description |
|---|---|---|
mimerequired | string | image/*, application/pdf, text/*, audio/*, video/*, JSON, ZIP, XML or Office types. |
sizerequired | number | Bytes (25 MB max by default). |
Response
{
"ok": true,
"fileId": "0e6f…",
"uploadUrl": "/__appbricx/files/direct?fileId=0e6f…&sig=…&mime=image%2Fpng",
"method": "POST"
}Errors
| Status | Code | When |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key"). |
| 401 | none | Not signed in. |
| 415 | MIME_NOT_ALLOWED | Type not allowed. |
| 400 | INVALID_SIZE | size missing or zero. |
| 413 | TOO_LARGE | Over the limit. |
| 429 | (rate limit) | Too many uploads. |
curl -X POST "$APP_ORIGIN/__appbricx/files/sign" \
-H "Authorization: Bearer $APP_KEY" \
-H "x-appbricx-app-session: $APP_SESSION" \
-H "content-type: application/json" \
-d '{"mime":"image/png","size":182044}'const res = await fetch(`${APP_ORIGIN}/__appbricx/files/sign`, {
method: "POST",
headers: {
Authorization: `Bearer ${APP_KEY}`,
"x-appbricx-app-session": APP_SESSION,
"content-type": "application/json",
},
body: JSON.stringify({
"mime": "image/png",
"size": 182044
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);Source: services/api/src/routes/app-files.ts:157
Upload a file
POST/__appbricx/files/direct
multipart/form-data with a file field, to the uploadUrl from /files/sign (a direct post without the signature gets a fresh id).
- Auth
- App key + signed-in user:
Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Query parameters
| Name | Type | Description |
|---|---|---|
fileIdoptional | string | From /files/sign. |
sigoptional | string | From /files/sign. |
mimeoptional | string | Fallback type. |
Body
| Name | Type | Description |
|---|---|---|
filerequired | File | The file. |
Response
{
"ok": true,
"fileId": "0e6f…",
"size": 182044,
"mime": "image/png",
"originalName": "avatar.png"
}Errors
| Status | Code | When |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid Authorization bearer ("Missing Authorization: Bearer <token>", "Invalid API key"). |
| 400 | INVALID_MULTIPART | Not multipart. |
| 400 | MISSING_FILE | No file field. |
| 415 | MIME_NOT_ALLOWED | Type not allowed. |
| 413 | TOO_LARGE | Over the limit. |
| 500 | STORAGE_ERROR | Object store write failed. |
| 500 | META_INSERT_FAILED | Metadata write failed (the object is removed). |
curl -X POST "$APP_ORIGIN/__appbricx/files/direct?fileId=0e6f%E2%80%A6&sig=%E2%80%A6" \
-H "Authorization: Bearer $APP_KEY" \
-H "x-appbricx-app-session: $APP_SESSION" \
-F "file=@avatar.png"const res = await fetch(`${APP_ORIGIN}/__appbricx/files/direct?fileId=0e6f%E2%80%A6&sig=%E2%80%A6`, {
method: "POST",
headers: {
Authorization: `Bearer ${APP_KEY}`,
"x-appbricx-app-session": APP_SESSION,
},
body: form, // const form = new FormData(); form.append("file", file);
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);Source: services/api/src/routes/app-files.ts:192
Download a file
GET/__appbricx/files/:id
The file's bytes, if the session can see its metadata row. Images and PDF are served inline; anything else as an attachment, always with nosniff and a sandboxing CSP.
- Auth
- App key + signed-in user:
Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Path parameters
| Name | Type | Description |
|---|---|---|
:idrequired | string | The file id. |
Query parameters
| Name | Type | Description |
|---|---|---|
envoptional | "dev" | "prod" | The environment the file was uploaded to (app.upload puts it in the URL). |
Response
<bytes> (content-type: image/png)Errors
| Status | Code | When |
|---|---|---|
| 400 | INVALID_ID | Not a uuid. |
| 404 | NOT_FOUND | Missing, deleted, or not visible to this user. |
curl "$APP_ORIGIN/__appbricx/files/0e6f…?env=prod" \
-H "Authorization: Bearer $APP_KEY" \
-H "x-appbricx-app-session: $APP_SESSION"const res = await fetch(`${APP_ORIGIN}/__appbricx/files/0e6f…?env=prod`, {
headers: {
Authorization: `Bearer ${APP_KEY}`,
"x-appbricx-app-session": APP_SESSION,
},
});
const text = await res.text();Source: services/api/src/routes/app-files.ts:248
Delete a file
DELETE/__appbricx/files/:id
Soft-delete a file the user owns.
- Auth
- App key + signed-in user:
Authorization: Bearer $APP_KEYx-appbricx-app-session: $APP_SESSION
Path parameters
| Name | Type | Description |
|---|---|---|
:idrequired | string | The file id. |
Response
{
"ok": true
}Errors
| Status | Code | When |
|---|---|---|
| 400 | INVALID_ID | Not a uuid. |
| 500 | DB_ERROR | The metadata update failed. |
curl -X DELETE "$APP_ORIGIN/__appbricx/files/0e6f…" \
-H "Authorization: Bearer $APP_KEY" \
-H "x-appbricx-app-session: $APP_SESSION"const res = await fetch(`${APP_ORIGIN}/__appbricx/files/0e6f…`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${APP_KEY}`,
"x-appbricx-app-session": APP_SESSION,
},
});
const data = await res.json();
if (!res.ok) throw new Error(data.error?.message ?? data.error ?? res.statusText);Source: services/api/src/routes/app-files.ts:304