API Documentation

Upload and Edit APIs

Upload and Edit APIs

Shared Concepts

  • hname: host/domain where link is allocated (file.ax, file.wf, file.yt, kt.ci, gatto.me with permission rules).
  • manager: owner token used for ownership checks.
  • folderId: optional folder assignment field supported by upload/creation endpoints.
  • Secondary sessions can upload/create; list/edit behavior is controlled by per-secondary flags (can_list_files, can_edit_files), plus upload-token and folder-scope checks.

Authentication Requirements (As Implemented)

Endpoint Auth Required (as implemented)
GET /api None
POST /api/initChunkedUpload Cookie session or API key auth
POST /api/uploadChunk No explicit auth middleware; valid upload id required
GET /api/chunkedUploadStatus No explicit auth middleware; valid upload id required
POST /api/finishChunkedUpload No explicit auth middleware; handler requires valid chunk session plus body fields (id, filename, manager value source)
POST /api/replaceFile Cookie session or API key auth + ownership checks; secondary session must have edit permission and match upload/file token and folder scope
PATCH /api/files/:id/folder Cookie session or API key auth + application/json; secondary restricted by token + folder scope
POST /api/files/move Cookie session or API key auth + application/json; secondary restricted by token + folder scope
POST /api/edit/:hname/:path Owner proof via body manager token or owner cookie session; secondary session must have edit permission and match file token + folder scope
POST /api/shorten Cookie session or API key auth + application/json; non-JSON requests are rejected; secondary scope applied
POST /api/html/paste Session pasteCSRF match + manager token (session or body); secondary scope applied
GET /api/editPaste/:hname/:path Owner cookie session required (otherwise redirect); secondary must have edit permission and pass scope checks

Credential-body script endpoints are documented in Plain Endpoints (Scripts).

Secondary Folder Scope Behavior

  • If secondary password has no folder scope: default token-based restrictions apply.
  • If secondary password has a folder scope:
    • create/upload endpoints treat missing folderId as “use scope root”
    • provided folderId must be the scoped folder or one of its descendants
    • edit/move/replace operations are rejected for files outside that subtree
  • If secondary credential has can_edit_files = false, edit/replace/move operations are denied even inside scope.

Chunked Uploads: Resumable + High Performance

Chunked uploads are the recommended path for large files.

  • Resumable: retry only failed chunks.
  • Network-tolerant: upload continues chunk by chunk on unstable links.
  • Idempotent finalize: repeated finalize calls return the same completed result.
  • Optional temporary hold: browser clients can reserve the final share URL during init, before all chunks have uploaded.

Chunked Flow

  1. Initialize with filename + full size.
  2. Split file client-side into numbered chunks (chunk=1, chunk=2, …).
  3. Upload each chunk with upload id.
  4. Retry failed chunks only.
  5. Optionally poll status.
  6. Finalize after all chunks are uploaded.
  7. If finalize returns processing, retry shortly.

Temporary Upload Holds

Temporary holds are opt-in for clients that need to show/share the final URL before upload completion.

  • Enabled by sending reserveTemporaryHold: true to POST /api/initChunkedUpload.
  • The init response includes the public link, hname, and resourceType: 3.
  • File metadata edits use the normal POST /api/edit/:hname/:path route while the upload is in progress.
  • On finalize, the reserved URL becomes the final file URL.
  • Clients that do not send reserveTemporaryHold: true keep the legacy behavior: URL allocation happens during finalize.
  • Expired unfinished uploads also expire their reserved URL.

Request and Response Examples

GET /api

Success response (200, plain text):

Hello World

POST /api/initChunkedUpload

Auth requirement:

  • Active authenticated session is required.
  • You can satisfy this with either:
    • normal browser/session cookie auth, or
    • API key headers (Authorization: Bearer <api_key> or X-API-Key) when API-key middleware is enabled.

Request body (application/json or urlencoded):

{
  "filename": "video.mp4",
  "size": 104857600
}

Success response (200):

{
  "id": "3fa1c7409df3a2d4bbf7d33d5e6f7c18",
  "storageInfo": {
    "usage": 123456,
    "limit": 53687091200,
    "remaining": 53686967744
  }
}

Temporary-hold request body (application/json or urlencoded):

{
  "filename": "video.mp4",
  "size": 104857600,
  "reserveTemporaryHold": true,
  "randomizeFileName": false,
  "password": "optional-file-password",
  "skipEmbeddedPage": false,
  "forceDownload": false,
  "contentType": "video/mp4",
  "expiry": "2030-01-01T00:00:00.000Z",
  "linkSize": 8,
  "keepExtensionInURL": true,
  "folderId": 123,
  "hname": "file.ax"
}

Temporary-hold success response (200):

{
  "id": "3fa1c7409df3a2d4bbf7d33d5e6f7c18",
  "link": "abcde.mp4",
  "hname": "file.ax",
  "resourceType": 3,
  "storageInfo": {
    "usage": 123456,
    "limit": 53687091200,
    "remaining": 53686967744
  }
}

Storage failure (413):

{
  "error": "Storage limit exceeded",
  "details": "...",
  "usage": 53687000000,
  "limit": 53687091200,
  "remaining": 91200
}

POST /api/uploadChunk

Request format:

  • Query: id=<upload-id>&chunk=<number>
  • Multipart field: file

Example:

curl -X POST \
  -F "file=@chunk-1.bin" \
  "https://file.ax/api/uploadChunk?id=3fa1c7409df3a2d4bbf7d33d5e6f7c18&chunk=1"

Success response (200):

{ "success": true }

GET /api/chunkedUploadStatus

Request query:

id=<upload-id>

Possible responses:

{ "status": "pending" }
{ "status": "processing" }
{
  "status": "completed",
  "success": true,
  "link": "abcde",
  "hname": "file.ax"
}
{ "error": "Upload not found", "status": "not_found" }

POST /api/finishChunkedUpload

Request body (application/json or urlencoded):

{
  "id": "3fa1c7409df3a2d4bbf7d33d5e6f7c18",
  "filename": "video.mp4",
  "_manager": "manager_token",
  "folderId": 123,
  "keepExtensionInURL": true,
  "linkSize": 6,
  "hname": "file.ax",
  "forceDownload": false,
  "skipEmbeddedPage": false
}

Success response (200):

{
  "success": true,
  "link": "abcde.mp4",
  "hname": "file.ax"
}

When the upload was initialized with a temporary hold, finalize returns the same response shape and keeps the reserved URL.

Processing response (202):

{
  "status": "processing",
  "message": "Upload is currently being finalized. Please retry shortly.",
  "retryAfter": 5
}

POST /api/replaceFile

Request body (application/json or urlencoded):

{
  "id": "3fa1c7409df3a2d4bbf7d33d5e6f7c18",
  "replaceHname": "file.ax",
  "replacePath": "old-link",
  "newFilename": "new-name.mp4",
  "reinferContentType": true
}

Success response (200):

{
  "success": true,
  "link": "old-link",
  "hname": "file.ax",
  "oldLink": "old-link_old",
  "newFilename": "new-name.mp4"
}

POST /api/edit/:hname/:path

Request headers:

  • Content-Type: application/json (required)

Request body example (metadata update):

{
  "manager": "manager_token",
  "filename": "renamed.mp4",
  "contentType": "video/mp4",
  "password": "optional-file-password",
  "expiry": "2030-01-01T00:00:00.000Z",
  "forceDownload": true,
  "skipEmbeddedPage": false,
  "path": "custom-link",
  "hname": "file.ax"
}

Delete example:

{ "manager": "manager_token", "delete": true }

Success response (200):

  • Update: full updated file metadata object.
  • Delete: { "success": true }

PATCH /api/files/:id/folder

Request headers:

  • Content-Type: application/json (required)

Request body:

{ "folderId": 123 }

Success response (200):

{ "success": true, "id": 987, "folderId": 123 }

POST /api/files/move

Request headers:

  • Content-Type: application/json (required)

Request body:

{ "fileIds": [987, 988], "folderId": 123 }

Success response (200):

{ "success": true, "moved": 2, "ids": [987, 988] }

POST /api/shorten

Request headers:

  • Content-Type: application/json (required)

Request body (application/json):

{
  "folderId": 123,
  "dest": "https://example.com/docs",
  "expiry": "2030-01-01T00:00:00.000Z",
  "path": "docs",
  "hname": "file.ax"
}

Success response (200):

{
  "success": true,
  "link": "docs",
  "hname": "file.ax",
  "dest": "https://example.com/docs"
}

Failure example (415):

{ "error": "Content-Type must be application/json" }

POST /api/html/paste

Request format:

  • Multipart form (no file)
  • Required fields: text, pasteCSRF

Example:

curl -X POST https://file.ax/api/html/paste \
  -F "text=hello world" \
  -F "pasteCSRF=<session_csrf>" \
  -F "expiry=7d" \
  -F "folderId=123" \
  -F "extension=txt" \
  -F "manager=<manager_token>"

Success response:

  • 302 redirect to https://<hname>/<path>

Failure example (403):

{ "error": "Invalid CSRF token" }

GET /api/editPaste/:hname/:path

Behavior:

  • If session owns the file, returns paste editor HTML.
  • If not owner or invalid file, redirects to public file URL or https://file.ax.