Files
File upload, attachment, and retrieval API in NapX PMS.
Files
NapX PMS provides a file storage API that lets you upload documents and media, attach them to platform entities, and generate time-limited download URLs. Files are stored in S3 (or an in-memory fallback for development) under a tenant-scoped key scheme.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /v1/files/upload-url | Create a presigned upload URL for direct-to-S3 uploads |
| POST | /v1/files/upload | Upload a file (up to 10 MB); optionally attach to an entity |
| GET | /v1/files/:id/url | Get a presigned download URL |
| POST | /v1/files/attach | Attach an already-uploaded file to a platform entity |
| GET | /v1/files/attachments | List files attached to an entity (?entityType=&entityId=) |
| DELETE | /v1/files/attachments/:id | Delete an attachment and remove the backing file if it is no longer referenced |
| DELETE | /v1/files/:id | Delete a file record, all its attachments, and the backing S3 object |
Response Shape
POST /v1/files/uploadreturns{ file: FileRecord, attachment?: FileAttachmentRecord }. Theattachmentfield is included only whenentityTypeandentityIdquery params are provided.POST /v1/files/upload-urlreturns{ uploadUrl, fileId, expiresIn }so the client can upload bytes directly to S3 after the file row has been created.GET /v1/files/:id/urlreturns{ url: string }— a presigned URL valid for 15 minutes by default (configurable via?expiresIn=<seconds>).POST /v1/files/attachreturns aFileAttachmentRecord.GET /v1/files/attachmentsreturns an array ofFileAttachmentRecordrows.DELETE /v1/files/attachments/:idreturns204 No Content.DELETE /v1/files/:idreturns204 No Content. Resolves silently when the file does not exist or belongs to another tenant (no information leakage).
Polymorphic Attachment Targets
Files can be attached to any of the following entity types:
| entityType | Description |
|---|---|
property | A property record |
room | A room within a property |
space | A bookable space |
spaceType | A space type/category |
guest | A guest profile |
reservation | A reservation record |
user | A platform user account |
Security Model
- Every request requires
Authorization: Bearer <session-token>. - Tenant context is derived from validated auth claims; files outside the caller's tenant are not accessible.
- Presigned download URLs are generated by the storage provider and expire after the configured window (default: 900 seconds).
File Size Limit
Uploads are capped at 10 MB per file. Multipart uploads are validated server-side, and direct
uploads via /v1/files/upload-url require fileSize and reject the request before URL issuance when
the declared size is missing or above the limit.
In addition, direct-upload issuance is subject to a tenant monthly upload quota (configured via
FILES_TENANT_MONTHLY_UPLOAD_LIMIT_BYTES; default 5 GB). When the quota would be exceeded,
upload URL issuance is rejected with 400 Bad Request.
File Deletion
DELETE /v1/files/:id is intended for cleaning up orphaned file records — for example, when a
presigned upload to S3 fails after the file row has been created. The call:
- Deletes all
fileAttachmentrows linked to the file. - Removes the backing S3 object (best-effort; a storage failure is logged as a warning and does not abort the database cleanup).
- Deletes the file row itself.
All three steps are wrapped in a single transaction. Requesting deletion of a non-existent file or a
file belonging to a different tenant returns 204 silently.
Error Handling
400 Bad Requestwhen file size exceeds 10 MB or an invalidentityTypeis provided.401 Unauthorizedwhen the bearer token is missing or invalid.404 Not Foundwhen a file ID does not exist for the tenant.
Example
POST /v1/files/upload?entityType=reservation&entityId=0d2d70e1-aeab-432f-ae94-9f3f5a42ba55
Authorization: Bearer <session-token>
Content-Type: multipart/form-data
[file field: signed-lease.pdf]
See the API reference for the detailed endpoint contract including all query parameters and response fields.