# Fileserver HTTP contract Every public endpoint is listed here. `FileserverDocumentationCoverageTest` scans the controllers and fails if one is missing, so this file cannot silently fall behind the code. ## Public endpoints | Method | Path | Success | Notes | |---|---|---|---| | POST | `/v1/files` | `201` READY, `202` VERIFYING | multipart single upload | | POST | `/v1/files:raw` | `201`, `202` | the whole request body is the file | | POST | `/v1/files:batch` | `200` | ordered per-part results; explicitly non-atomic | | GET | `/v1/files/{fileId}` | `200` | public metadata; never a content key or path | | GET | `/v1/files/{fileId}/content` | `200`, `206`, `304` | download | | HEAD | `/v1/files/{fileId}/content` | `200`, `304` | identical headers, no body | | DELETE | `/v1/files/{fileId}` | `202`, `204` | logical delete first | | POST | `/v1/files/{fileId}:copy` | `202` | create-only target | | POST | `/v1/files/{fileId}:move` | `200` | logical namespace change only | | OPTIONS | `/v1/uploads` | `204` | tus capability discovery | | POST | `/v1/uploads` | `201` | tus creation | | HEAD | `/v1/uploads/{uploadId}` | `204` | tus offset | | PATCH | `/v1/uploads/{uploadId}` | `204` | tus append | | DELETE | `/v1/uploads/{uploadId}` | `204` | tus termination | | POST | `/v1/experimental/draft12/uploads` | `201` | Experimental; off by default | | PATCH | `/v1/experimental/draft12/uploads/{uploadId}` | `204` | Experimental; off by default | ## Management endpoints Reachable only where both `app.fileserver-platform.enabled=true` and `app.fileserver-platform.admin.enabled=true`, gated at the servlet chain on `app.fileserver-platform.security.admin-roles`, and intended for a management port rather than the public one. | Method | Path | |---|---| | GET | `/internal/fileserver/storage-health` | | GET | `/internal/fileserver/capabilities` | | GET | `/internal/fileserver/orphans` | | POST | `/internal/fileserver/orphans:reconcile` | | POST | `/internal/fileserver/files/{fileId}:reverify` | | POST | `/internal/fileserver/files/{fileId}:force-delete` | | GET | `/internal/fileserver/uploads/incomplete` | | POST | `/internal/fileserver/uploads:cleanup` | ## Status codes | Status | Condition | |---:|---| | `200` | metadata, full GET, batch result, move | | `201` | file or upload created | | `202` | verification or physical cleanup deferred | | `204` | append, cancel, bodyless update | | `206` | satisfiable Range | | `304` | validator matched on GET or HEAD | | `400` | malformed header or header combination | | `401` | unauthenticated | | `403` / `404` | denied, or hidden under the existence-hiding profile | | `409` | state, offset, or lease conflict | | `410` | expired upload resource | | `411` | `require-content-length` profile with no length | | `412` | precondition failed | | `413` | size or quota policy violation | | `415` | upload media type not accepted | | `416` | unsatisfiable Range; carries the real length | | `422` | digest, signature, or scanner rejection | | `429` | transfer admission or rate limit | | `503` | storage or scanner unavailable | | `504` | downstream timeout | | `507` | out of storage capacity | ## Failure body Every failure answers `application/problem+json` with a stable code and its URN: ```json { "type": "urn:fileserver:problem:upload-offset-mismatch", "title": "Upload offset mismatch", "status": 409, "code": "UPLOAD_OFFSET_MISMATCH", "retryable": true, "ambiguous": false, "reconciliationRequired": false, "traceId": "..." } ``` The server-side exception message never appears. `ambiguous` is the field a client must read before retrying: an ambiguous failure may already have taken effect. ## Header contract | Header | Contract | |---|---| | `Content-Type` | client value is a claim; the verified type is stored separately | | `Content-Disposition` | `attachment` by default; scriptable types are never inline | | `Accept-Ranges` | `bytes` | | `Range` | single range by default; multi-range only under an explicit budget | | `Content-Range` | actual range on `206`; the unsatisfied form on `416` | | `ETag` | strong validator derived from the SHA-256 | | `Last-Modified` | metadata publication instant, never a filesystem timestamp | | `Cache-Control` | `private, no-store` by default | | `X-Content-Type-Options` | always `nosniff` on a download | | `Retry-After` | on retryable `409`, `429`, `503`, and `504` | | `X-Accel-Redirect` | internal only; never forwarded to a client |