Vaulx uses a two-step upload flow that keeps file bytes off the application server entirely. The client first asks the Vaulx API to create a pending file record and receive a short-lived presigned S3 PUT URL. The client then PUTs the raw file bytes straight to S3 using that URL. Finally, the client notifies the Vaulx server to mark the file active, which records the upload in the audit log and makes the file visible in the file browser.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/noelzappy/vaulx/llms.txt
Use this file to discover all available pages before exploring further.
Both endpoints require an authenticated session. The authenticated user must hold the editor or admin role. A viewer-only session will receive a
403 Forbidden response.Full upload flow
POST /api/upload/init — Request a presigned URL
Send a JSON body describing the file you want to upload. The server creates a file record with ResponseThe S3 object key is generated as
status = 'pending' and returns a presigned S3 PUT URL alongside the new file’s UUID.Request bodyThe original filename. Vaulx sanitizes this value before using it as the S3 object name: any character that is not a letter, digit,
., -, or _ is replaced with _. The unsanitized name is stored in the database as the display name.File size in bytes. This value is embedded in the presigned URL signature — the subsequent S3 PUT must send exactly this many bytes via
Content-Length, or S3 will reject the request.MIME type of the file (e.g.
image/jpeg, video/mp4). Used as the S3 Content-Type. If omitted, the Content-Type header on the PUT request is left unconstrained by the signature.UUID of the destination folder. Omit the field or pass an empty string to place the file at the root level.
UUID of the newly created file record. Save this — you will need it to call the confirm endpoint after the S3 PUT completes.
Presigned S3 PUT URL. The URL is valid for 15 minutes. PUT the raw file bytes to this URL during that window. The URL encodes the
Content-Type and Content-Length constraints derived from mime_type and size, so those headers must match exactly.files/<16-hex-bytes>/<sanitized-name>. For example, a file named my photo.jpg stored in the bucket will have a key such as files/a1b2c3d4e5f6a1b2/my_photo.jpg.PUT the file bytes directly to S3
Issue an HTTP PUT directly from the browser or client to the A successful PUT returns HTTP
upload_url returned in step 1. The Vaulx server is not involved in this transfer — the bytes go directly to S3.You must include Content-Type and Content-Length headers whose values match the mime_type and size sent in step 1. S3 validates these against the presigned URL signature and will return a 403 if they differ.Example with curl200 with an empty body. If S3 returns a non-2xx status, do not call the confirm endpoint — the file will remain in status = 'pending' and can be retried or cleaned up.POST /api/upload/confirm/{fileID} — Confirm the upload
Once the S3 PUT succeeds, notify the Vaulx server that the upload is complete. The server sets the file’s status to
ResponseThe response also includes the Error responses
active and writes a file.upload audit log entry.Path parameter| Parameter | Type | Description |
|---|---|---|
fileID | string | The UUID returned as file_id from the init endpoint |
HX-Trigger header carrying a showToast event so that HTMX-driven UIs can display a success notification without extra JavaScript:| Status | Condition |
|---|---|
400 | fileID path parameter is not a valid UUID |
403 | Authenticated user is not the uploader and is not admin |
404 | File record not found, or file is already active |
Filename sanitization
Before the S3 key is constructed, the filename is passed through a sanitization step. The path component is stripped (everything up to and including the last/ or \), then every remaining character that is not a Unicode letter, Unicode digit, ., -, or _ is replaced with _. If the result is an empty string, the name falls back to file.
| Original name | Sanitized S3 segment |
|---|---|
my photo.jpg | my_photo.jpg |
résumé (final).pdf | résumé__final_.pdf |
../../../etc/passwd | ______etc_passwd |
report_2024-01.xlsx | report_2024-01.xlsx |
The presigned PUT URL expires 15 minutes after it is issued. Call
POST /api/upload/confirm/{fileID} promptly once the S3 PUT completes. If the URL expires before the PUT is attempted, discard the pending file record and restart the flow from the init endpoint.