Upload an object
Uploads a file and returns its stored representation, including the URL you serve it from.
POST /api/v1/objects
Permission: write · Content-Type: multipart/form-data
Request
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | Yes | A key with write permission. |
X-App-Id | If the key is app-restricted | Your mobile bundle id (e.g. com.example.myapp). |
Do not set Content-Type manually in browsers/fetch — let the client set the multipart boundary.
Form fields
| Field | Required | Type | Description |
|---|---|---|---|
file | Yes | file | The file to store. Validated against the max upload size (default 10 MB; configurable per deployment) and any configured allowed-MIME list. |
visibility | No | public | private | Access control. Omitted → private. Integrations send public. |
expires_in_days | No | integer (1–3650) | Auto-delete this many days from now. |
expires_at | No | ISO-8601 datetime (future) | Auto-delete at this absolute time. Wins over expires_in_days if both are sent. |
Examples
curl
curl -X POST https://fileshub.zaions.com/api/v1/objects \
-H "X-API-Key: fh_live_xxx" \
-F "file=@/path/to/report.pdf" \
-F "visibility=public" \
-F "expires_in_days=7"
fetch
const form = new FormData();
form.append('file', file); // a File/Blob
form.append('visibility', 'public');
const res = await fetch('https://fileshub.zaions.com/api/v1/objects', {
method: 'POST',
headers: { 'X-API-Key': 'fh_live_xxx' },
body: form,
});
const object = await res.json();
PHP (Guzzle)
$response = $client->post('https://fileshub.zaions.com/api/v1/objects', [
'headers' => ['X-API-Key' => 'fh_live_xxx'],
'multipart' => [
['name' => 'file', 'contents' => fopen('/path/report.pdf', 'r')],
['name' => 'visibility', 'contents' => 'public'],
],
]);
$object = json_decode((string) $response->getBody(), true);
Response
201 Created
{
"public_id": "01JDKQXXXXXXXXXXXXXXXXXXXXX",
"project_id": "01JDKPXXXXXXXXXXXXXXXXXXXXX",
"visibility": "public",
"mime_type": "application/pdf",
"size_bytes": 1048576,
"url": "https://fileshub.zaions.com/api/v1/objects/01JDKQXXXXXXXXXXXXXXXXXXXXX",
"expires_at": "2026-06-30T12:00:00+00:00"
}
Persist url (and optionally public_id) on your own record. expires_at is null when no expiry was requested.
Errors
| Status | When | Body |
|---|---|---|
401 | No / invalid X-API-Key. | { "message": "API key is required..." } |
403 | Key lacks write, or origin/app not allowed. | { "message": "..." } |
422 | Validation failed (no file, file too large, bad visibility, disallowed MIME). | { "message": "<first validation error>" } |
429 | Rate limit exceeded. | { "message": "..." } |
500 | Server error while storing. | { "message": "An error occurred while uploading the file." } |
Notes
- The
public_idis a ULID: time-sortable and URL-safe. - The stored file keeps its original filename for downloads (
Content-Disposition). - Set
visibilitydeliberately — see File visibility.