API Reference
Authentication, all endpoints, error codes, and response formats.
Before you begin
Section titled “Before you begin”- Base URL: the deployed origin of the Workers application, for example
https://{domain}. All paths in this reference are relative to that origin. - Authentication: each request uses one of three methods, depending on the client.
- CSRF tokens: cookie-authenticated write requests must include the
X-CSRF-Tokenheader. Obtain a token fromGET /api/auth/csrf-token. API-key and WebDAV requests skip CSRF checks. - Content type: send JSON request bodies with
Content-Type: application/json. File uploads usemultipart/form-dataor a raw body. - Rate limits: auth endpoints allow 5 requests per minute per IP. Other endpoints apply a configurable per-user and per-IP limit.
Authentication methods
Section titled “Authentication methods”| Method | Header | Use for |
|---|---|---|
| HttpOnly cookie JWT | Cookie: auth_token=... | Web frontend and browser clients |
| API key (Bearer) | Authorization: Bearer {key_id}.{secret} | PicGo, PicList, scripts, and custom clients |
| WebDAV Basic | Authorization: Basic base64({key_id}:{secret}) | WebDAV clients |
The API key is an opaque token in the format pk_{24 chars}.sk_{48 chars}. The server stores only a SHA-256 hash of the full token, so you cannot retrieve it again after creation.
Response format
Section titled “Response format”Every successful response uses the same envelope.
{ "success": true, "data": { }, "message": "optional message", "timestamp": 1710000000000}Success response fields
Section titled “Success response fields”| Field | Type | Description |
|---|---|---|
success | boolean | Always true for successful responses. |
data | object | The resource payload. The shape depends on the endpoint. |
message | string | An optional human-readable message. |
timestamp | integer | The server time in milliseconds since the Unix epoch. |
Failed requests return an error envelope with an HTTP status code and a machine-readable error code.
{ "success": false, "error": { "code": "NOT_FOUND", "message": "文件不存在", "details": {} }, "timestamp": 1710000000000}Error response fields
Section titled “Error response fields”| Field | Type | Description |
|---|---|---|
success | boolean | Always false for error responses. |
error.code | string | A stable machine-readable code such as NOT_FOUND. |
error.message | string | A human-readable message. |
error.details | object | Additional details. Present only in development environments. |
timestamp | integer | The server time in milliseconds since the Unix epoch. |
Error codes
Section titled “Error codes”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A request field or query parameter has an invalid value. | Correct the field and retry. |
INVALID_CREDENTIALS | 401 | The username or password is wrong. | Re-enter the credentials. |
UNAUTHORIZED | 401 | The request has no valid session or API key. | Log in or provide a valid key. |
INVALID_TOKEN | 401 | The session token, API key, or download token is invalid or expired. | Refresh the credential and retry. |
INVALID_PASSWORD | 401 | A file, folder, or share password is incorrect. | Re-enter the password. |
USER_DISABLED | 401 | The account is not active. | Contact the administrator. |
ROLE_CHANGED | 401 | The account role changed since the session started. | Log in again. |
SESSION_REVOKED | 401 | The session ended after a password change or logout. | Log in again. |
EMAIL_NOT_VERIFIED | 403 | Login requires email verification. | Verify the email first. |
FORBIDDEN | 403 | The caller lacks permission for the operation. | Check the permission rules and the API key scope. |
PASSWORD_REQUIRED | 403 | The file is password-protected and the password is not verified. | Call the password-verify endpoint first. |
NOT_FOUND | 404 | The resource, file, mount, or path does not exist. | Confirm the identifier or path and retry. |
ALREADY_EXISTS | 409 | A file or folder with the same name already exists. | Use a different name. |
OPERATION_FAILED | 409 / 422 | The operation cannot proceed because of the current state. | Check the error message and retry. |
SHARE_EXPIRED | 410 | The share link has expired. | Ask the creator for a new link. |
SHARE_REVOKED | 410 | The share link no longer works. | Ask the creator for a new link. |
SHARE_LIMIT_REACHED | 410 | The share hit its view or download limit. | Ask the creator to raise the limit. |
UPLOAD_SESSION_EXPIRED | 410 | The upload session exceeded its one-hour lifetime. | Start a new upload session. |
QUOTA_EXCEEDED | 413 | The storage or file-count quota has run out. | Free up space or raise the quota. |
PAYLOAD_TOO_LARGE | 413 | The upload exceeds the 1 GB free-mode limit. | Split the file or use a smaller file. |
RATE_LIMIT_EXCEEDED | 429 | The caller exceeded a rate limit. | Wait and retry, or raise the limit. |
INTERNAL_ERROR | 500 | An unexpected server error occurred. | Retry later or report the issue. |
Authentication
Section titled “Authentication”Authentication endpoints manage registration, login, sessions, email verification, and password reset. Registration, login, logout, and password endpoints are public; GET /api/auth/me and GET /api/auth/csrf-token require a logged-in session.
Register a user
Section titled “Register a user”Creates a user account and, when the site requires email verification, sends a verification link.
POST /api/auth/register
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | 3 to 20 characters. Letters, digits, and underscores only. |
password | string | Yes | At least 8 characters, at most 128. |
email | string | Yes | A valid email address. |
inviteCode | string | No | The invite code, required when invite codes are active. |
turnstileToken | string | No | The Turnstile token, required when Turnstile is active. |
Response
Section titled “Response”Returns the new user and a confirmation message with status 201.
{ "success": true, "data": { "user": { "id": "uuid", "username": "alice", "email": "alice@example.com", "emailVerified": false, "role": "user" }, "message": "注册成功" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A field violates the format rules. | Correct the field and retry. |
FORBIDDEN | 403 | This site does not allow registration. | Contact the administrator. |
ALREADY_EXISTS | 409 | The username or email is already registered. | Choose another username or email. |
Example
Section titled “Example”curl -X POST https://{domain}/api/auth/register \ -H "Content-Type: application/json" \ -d '{"username":"alice","password":"secret-pass","email":"alice@example.com"}'Log in
Section titled “Log in”Authenticates a user and sets an HttpOnly auth_token cookie for 7 days.
POST /api/auth/login
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | The username. |
password | string | Yes | The password. |
turnstileToken | string | No | The Turnstile token, required when Turnstile is active. |
Response
Section titled “Response”Returns the user and the current quota.
{ "success": true, "data": { "user": { "id": "uuid", "username": "alice", "email": "alice@example.com", "emailVerified": true, "role": "user", "displayName": "Alice", "avatarUrl": null, "defaultPath": "/", "locale": "zh-CN", "theme": "system" }, "quota": { "maxStorage": 10737418240, "usedStorage": 0, "maxFiles": 1000, "usedFiles": 0 } }, "timestamp": 1710000000000}The Set-Cookie header carries the auth_token JWT with HttpOnly, SameSite=Strict, and a 7-day lifetime.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
INVALID_CREDENTIALS | 401 | The username or password is wrong. | Re-enter the credentials. |
USER_DISABLED | 401 | The account is not active. | Contact the administrator. |
EMAIL_NOT_VERIFIED | 403 | Login requires email verification. | Verify the email first. |
Example
Section titled “Example”curl -X POST https://{domain}/api/auth/login \ -H "Content-Type: application/json" \ -c cookies.txt \ -d '{"username":"alice","password":"secret-pass"}'Log out
Section titled “Log out”Revokes the current session and clears the auth_token cookie. Logout bumps the session version, which invalidates every JWT issued for the account.
POST /api/auth/logout
Response
Section titled “Response”Returns data: null on success.
Example
Section titled “Example”curl -X POST https://{domain}/api/auth/logout \ -b cookies.txtGet the current user
Section titled “Get the current user”Returns the logged-in user and their quota.
GET /api/auth/me
Response
Section titled “Response”{ "success": true, "data": { "user": { "id": "uuid", "username": "alice", "email": "alice@example.com", "emailVerified": true, "role": "user", "displayName": "Alice", "defaultPath": "/", "locale": "zh-CN", "theme": "system" }, "quota": { "maxStorage": 10737418240, "usedStorage": 1048576, "maxFiles": 1000, "usedFiles": 3 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | No valid session cookie. | Log in first. |
Example
Section titled “Example”curl https://{domain}/api/auth/me -b cookies.txtGet a CSRF token
Section titled “Get a CSRF token”Returns a CSRF token for the logged-in session. Send this token in the X-CSRF-Token header of cookie-authenticated write requests. The server caches the token in KV for 2 hours.
GET /api/auth/csrf-token
Response
Section titled “Response”{ "success": true, "data": { "token": "32-char-random-string" }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/auth/csrf-token -b cookies.txtVerify an email
Section titled “Verify an email”Completes email verification with the token from the verification email. Both /verify-email and /verify are aliases. The endpoint returns an HTML confirmation page, not JSON.
GET /api/auth/verify-email?token={token}
GET /api/auth/verify?token={token}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The verification token from the email. Valid for 24 hours. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The token is missing, invalid, or expired. | Request a new verification email. |
Request a password reset
Section titled “Request a password reset”Sends a password-reset link to the email address. The response does not reveal whether the email belongs to an account.
POST /api/auth/forgot-password
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The registered email address. |
Response
Section titled “Response”{ "success": true, "data": { "message": "如果该邮箱已注册,重置链接已发送" }, "timestamp": 1710000000000}Example
Section titled “Example”curl -X POST https://{domain}/api/auth/forgot-password \ -H "Content-Type: application/json" \ -d '{"email":"alice@example.com"}'Reset the password
Section titled “Reset the password”Sets a new password with the token from the reset link. A successful reset revokes all existing sessions.
POST /api/auth/reset-password
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The reset token from the email. Valid for 15 minutes. |
password | string | Yes | The new password, at least 8 characters. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The token is invalid, expired, or the password is too short. | Request a new reset link. |
File endpoints list, create, update, move, and delete files and folders. All of them require a logged-in session, and each operation enforces path-level permission rules.
List files
Section titled “List files”Lists the children of a directory with pagination, sorting, filtering, and search.
GET /api/files?path={path}&page={page}&limit={limit}&sort={sort}&order={order}&type={type}&search={search}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
path | string | No | The directory to list. Defaults to /. |
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 100, maximum 1000. |
sort | string | No | name, time, size, or manual. Defaults to the mount setting. |
order | string | No | asc or desc. Defaults to asc. |
type | string | No | file or folder to filter by type. |
search | string | No | A keyword to match against file names. |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "uuid", "name": "photo.jpg", "path": "/drive/photos", "type": "file", "size": 1048576, "mimeType": "image/jpeg", "hasPassword": false, "ownerId": "uuid", "createdAt": 1710000000000, "updatedAt": 1710000000000 } ], "pagination": { "total": 12, "page": 1, "limit": 100, "pages": 1 }, "mount": { "id": "mount-id", "name": "Drive", "sortBy": "name", "sortOrder": "asc" } }, "timestamp": 1710000000000}Response fields
Section titled “Response fields”| Field | Type | Description |
|---|---|---|
items | array | The file and folder entries in the directory. |
items[].id | string | The file identifier. |
items[].name | string | The file or folder name. |
items[].path | string | The parent directory path. |
items[].type | string | file or folder. |
items[].size | integer | The size in bytes. |
items[].mimeType | string | The MIME type, for files. |
items[].hasPassword | boolean | Whether the file is password-protected. |
pagination | object | total, page, limit, and pages. |
mount | object | The mount that contains the directory. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A query parameter is invalid. | Correct the parameter and retry. |
NOT_FOUND | 404 | The path is not mounted. | Confirm the path. |
FORBIDDEN | 403 | The caller lacks read permission. | Check the permission rules. |
Example
Section titled “Example”curl "https://{domain}/api/files?path=/drive&limit=50" -b cookies.txtCreate a folder
Section titled “Create a folder”Creates a folder under the target path. Requires write permission on the target directory.
POST /api/files/folder
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | The parent directory path. |
name | string | Yes | The folder name, at most 255 characters. |
Response
Section titled “Response”Returns the created folder with status 201.
{ "success": true, "data": { "file": { "id": "uuid", "name": "photos", "path": "/drive", "type": "folder", "size": 0, "hasPassword": false, "createdAt": 1710000000000 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The name or path is invalid. | Correct the input and retry. |
FORBIDDEN | 403 | The caller lacks write permission. | Check the permission rules. |
NOT_FOUND | 404 | The parent path is not mounted. | Confirm the path. |
ALREADY_EXISTS | 409 | A file or folder with the same name already exists. | Choose a different name. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/folder \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"path":"/drive","name":"photos"}'Get file details
Section titled “Get file details”Returns a single file or folder with its permissions, access mode, and password status.
GET /api/files/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file identifier. |
Response
Section titled “Response”{ "success": true, "data": { "file": { "id": "uuid", "name": "photo.jpg", "path": "/drive/photos", "type": "file", "size": 1048576, "mimeType": "image/jpeg", "hasPassword": false, "createdAt": 1710000000000 }, "mount": { "id": "mount-id", "name": "Drive", "sortBy": "name", "sortOrder": "asc" }, "permissions": ["read", "write", "update", "delete", "share", "download"], "accessMode": "public_cdn", "hasPassword": false }, "timestamp": 1710000000000}The accessMode value is public_cdn for files served by a public CDN domain, signed_redirect for pre-signed URL providers, or private_gateway for the Worker download gateway.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The file or mount does not exist. | Confirm the identifier. |
FORBIDDEN | 403 | The caller lacks read permission. | Check the permission rules. |
Example
Section titled “Example”curl https://{domain}/api/files/{id} -b cookies.txtUpdate file metadata
Section titled “Update file metadata”Renames a file or folder and updates its metadata, including the access password and display options.
PUT /api/files/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file identifier. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | The new name. Renaming requires the update permission. |
customTitle | string | No | A custom display title, at most 200 characters. |
customColor | string | No | A custom accent color in #RRGGBB format. |
coverUrl | string | No | A cover image URL. |
iconEmoji | string | No | An icon emoji, at most 16 characters. |
accessPassword | string | No | A new access password, or null to remove it. The server stores only a hash. |
manualPosition | integer | No | The manual sort position. |
Response
Section titled “Response”Returns the updated file.
{ "success": true, "data": { "file": { "id": "uuid", "name": "renamed.jpg", "path": "/drive/photos", "type": "file", "size": 1048576, "hasPassword": true, "updatedAt": 1710000000000 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A field is invalid. | Correct the field and retry. |
FORBIDDEN | 403 | The caller lacks the update permission. | Check the permission rules. |
ALREADY_EXISTS | 409 | The new name collides with an existing entry. | Choose a different name. |
NOT_FOUND | 404 | The file does not exist. | Confirm the identifier. |
Example
Section titled “Example”curl -X PUT https://{domain}/api/files/{id} \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"name":"renamed.jpg","accessPassword":"my-pass"}'Verify a file password
Section titled “Verify a file password”Verifies the access password of a protected file and returns a short-lived gateway download URL.
POST /api/files/{id}/verify-password
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file identifier. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
password | string | Yes | The file access password. |
Response
Section titled “Response”{ "success": true, "data": { "url": "https://{domain}/api/gateway/download/{token}", "expiresIn": 900 }, "timestamp": 1710000000000}The returned URL stays valid for 900 seconds and works once.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The file has no password, or the password is missing. | Provide a password or skip verification. |
INVALID_PASSWORD | 401 | The password is wrong. | Re-enter the password. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/{id}/verify-password \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"password":"my-pass"}'Get a download link
Section titled “Get a download link”Returns a single-use gateway download URL for the file. The file must not be password-protected.
GET /api/files/{id}/download
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file identifier. |
Response
Section titled “Response”{ "success": true, "data": { "url": "https://{domain}/api/gateway/download/{token}", "expiresAt": 1710000900000 }, "timestamp": 1710000000000}The token expires 15 minutes after issue, and the gateway consumes it on the first download.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
PASSWORD_REQUIRED | 403 | The file is password-protected. | Call the password-verify endpoint first. |
FORBIDDEN | 403 | The caller lacks the download permission. | Check the permission rules. |
NOT_FOUND | 404 | The file does not exist. | Confirm the identifier. |
Example
Section titled “Example”curl https://{domain}/api/files/{id}/download -b cookies.txtGet copy links
Section titled “Get copy links”Returns the file URL in four formats: direct, HTML, Markdown, and BBCode. By default the direct URL points to the public path of the file, such as {origin}/drive/photos/photo.jpg. Pass signed=true to request a pre-signed URL from the provider, with the gateway URL as the fallback.
GET /api/files/{id}/copy-links?signed={signed}&expiresIn={expiresIn}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file identifier. |
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
signed | boolean | No | When true, request a signed URL. Defaults to false. |
expiresIn | integer | No | The signed URL lifetime in seconds, from 60 to 604800. Defaults to 3600. Used only with signed=true. |
Response
Section titled “Response”{ "success": true, "data": { "formats": { "direct": "https://{domain}/drive/photos/photo.jpg", "html": "<img src=\"https://{domain}/drive/photos/photo.jpg\" alt=\"photo.jpg\">", "markdown": "", "bbcode": "[img]https://{domain}/drive/photos/photo.jpg[/img]" }, "accessMode": "public_path", "needsPassword": false, "expiresIn": null }, "timestamp": 1710000000000}When you set signed=true, accessMode becomes signed and expiresIn returns the signed URL lifetime.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
FORBIDDEN | 403 | The caller lacks the download permission. | Check the permission rules. |
NOT_FOUND | 404 | The file does not exist. | Confirm the identifier. |
Example
Section titled “Example”curl "https://{domain}/api/files/{id}/copy-links?signed=true&expiresIn=3600" -b cookies.txtDelete a file
Section titled “Delete a file”Hard-deletes a file or folder. The metadata and quota update in a single transaction, and cleanup of the object runs asynchronously.
DELETE /api/files/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file or folder identifier. |
Response
Section titled “Response”{ "success": true, "data": { "deleted": 1, "size": 1048576 }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
FORBIDDEN | 403 | The caller lacks the delete permission. | Check the permission rules. |
NOT_FOUND | 404 | The file does not exist. | Confirm the identifier. |
Example
Section titled “Example”curl -X DELETE https://{domain}/api/files/{id} \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtMove a file
Section titled “Move a file”Moves or renames a file or folder asynchronously. The move uses a Saga: it copies the object, verifies the copy, switches the metadata atomically, then cleans up the source. Requires the delete permission on the source and the write permission on the target.
POST /api/files/{id}/move
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The file or folder identifier. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
targetPath | string | Yes | The target directory path. |
newName | string | No | An optional new name for the entry. |
Response
Section titled “Response”Returns the job identifier and its initial status.
{ "success": true, "data": { "jobId": "job-uuid", "status": "pending" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The target path is missing or invalid. | Provide a target path. |
FORBIDDEN | 403 | The caller lacks the required permissions. | Check the permission rules. |
NOT_FOUND | 404 | The file does not exist. | Confirm the identifier. |
OPERATION_FAILED | 409 | A conflict or a cycle would result. | Choose another target. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/{id}/move \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"targetPath":"/drive/archive"}'Get a job status
Section titled “Get a job status”Returns the status of an asynchronous operation, such as a move. Only the job owner can read it.
GET /api/files/jobs/{jobId}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
jobId | string | Yes | The job identifier from a move request. |
Response
Section titled “Response”{ "success": true, "data": { "job": { "id": "job-uuid", "type": "move", "status": "running", "progress": 40, "errorMessage": null, "createdAt": 1710000000000, "completedAt": null } }, "timestamp": 1710000000000}The status value is pending, running, completed, or failed. progress is a percentage from 0 to 100.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The job does not exist or belongs to another user. | Confirm the job identifier. |
Example
Section titled “Example”curl https://{domain}/api/files/jobs/{jobId} -b cookies.txtRun batch operations
Section titled “Run batch operations”Runs a delete or move operation over up to 100 files and folders. Each item runs independently, and the response lists the successful and failed items.
POST /api/files/batch
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
action | string | Yes | delete or move. |
fileIds | array | Yes | The file or folder identifiers, 1 to 100 items. |
targetPath | string | No | The target directory. Required for the move action. |
Response
Section titled “Response”{ "success": true, "data": { "succeeded": ["uuid-1", "uuid-2"], "failed": [{ "id": "uuid-3", "error": "文件不存在" }] }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The batch parameters are invalid. | Correct the parameters and retry. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/batch \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"action":"delete","fileIds":["uuid-1","uuid-2"]}'Uploads
Section titled “Uploads”Upload endpoints create an upload session, stream the object through the Worker or a pre-signed URL, and commit the file atomically. Sessions expire after one hour. Files larger than 100 MB use multipart upload automatically.
Create an upload session
Section titled “Create an upload session”Creates an upload session and atomically reserves quota. Files larger than 100 MB, or sessions with a partCount greater than 1, switch to multipart upload.
POST /api/files/upload-session
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
path | string | Yes | The target directory path. |
fileName | string | Yes | The file name, at most 255 characters. |
fileSize | integer | Yes | The file size in bytes, up to 20 GB. |
mimeType | string | No | The MIME type of the file. |
partCount | integer | No | The number of parts. Values greater than 1 enable multipart upload. |
idempotencyKey | string | No | A client-supplied key to resume a completed session. |
Response
Section titled “Response”{ "success": true, "data": { "sessionId": "session-uuid", "uploadUrl": "https://provider.example.com/presigned-upload", "uploadId": null, "uploadMode": "presigned", "totalParts": null, "parts": [], "expiresAt": 1710003600000, "expiresIn": 3600 }, "timestamp": 1710000000000}When the provider supports multipart pre-signed URLs, the response also returns parts, an array of { partNumber, url } entries for direct concurrent upload. Otherwise uploadMode is worker and you stream parts through the Worker.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A request field is invalid. | Correct the field and retry. |
FORBIDDEN | 403 | The caller lacks the write permission. | Check the permission rules. |
QUOTA_EXCEEDED | 413 | The storage or file-count quota has run out. | Free up space or raise the quota. |
NOT_FOUND | 404 | The target mount does not exist. | Confirm the path. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/upload-session \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"path":"/drive/photos","fileName":"photo.jpg","fileSize":1048576,"mimeType":"image/jpeg"}'Upload a raw file
Section titled “Upload a raw file”Uploads the file bytes directly through the Worker for a single-file session. Send the file bytes as the request body.
PUT /api/files/upload/raw/{sessionId}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session identifier from the upload session. |
Request headers
Section titled “Request headers”| Field | Type | Required | Description |
|---|---|---|---|
Content-Type | string | No | The MIME type of the file. Defaults to the session MIME type. |
Response
Section titled “Response”Returns the object ETag and size after verification.
{ "success": true, "data": { "etag": "\"abc123\"", "size": 1048576 }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The session does not exist or belongs to another user. | Start a new session. |
OPERATION_FAILED | 409 | The session is not in a pending state. | Start a new session. |
UPLOAD_SESSION_EXPIRED | 410 | The session exceeded its one-hour lifetime. | Start a new session. |
OPERATION_FAILED | 422 | The object size does not match the session. | Re-upload the file. |
Example
Section titled “Example”curl -X PUT https://{domain}/api/files/upload/raw/{sessionId} \ -H "Content-Type: image/jpeg" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ --data-binary @photo.jpgUpload a multipart part
Section titled “Upload a multipart part”Uploads one part of a multipart session through the Worker. The part size is 8 MB. The server records the returned ETag for resume and completion checks.
PUT /api/files/upload/multipart/{sessionId}/part/{partNumber}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session identifier. |
partNumber | integer | Yes | The part number, starting at 1. |
Response
Section titled “Response”{ "success": true, "data": { "partNumber": 1, "etag": "\"abc123\"" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The part number is out of range. | Use a valid part number. |
NOT_FOUND | 404 | The session does not exist. | Start a new session. |
OPERATION_FAILED | 409 | The session is not a multipart session. | Use a multipart session. |
UPLOAD_SESSION_EXPIRED | 410 | The session expired. | Start a new session. |
Example
Section titled “Example”curl -X PUT https://{domain}/api/files/upload/multipart/{sessionId}/part/1 \ -H "Content-Type: application/octet-stream" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ --data-binary @part1.binList multipart parts
Section titled “List multipart parts”Returns the uploaded and missing parts of a multipart session. This endpoint is the source of truth for resuming an interrupted upload; for pre-signed providers it also returns new pre-signed URLs for the missing parts.
GET /api/files/upload/multipart/{sessionId}/parts
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session identifier. |
Response
Section titled “Response”{ "success": true, "data": { "sessionId": "session-uuid", "totalParts": 4, "completedCount": 2, "parts": [{ "partNumber": 1, "etag": "\"abc123\"" }], "missingParts": [2, 3, 4], "presignedParts": [{ "partNumber": 2, "url": "https://provider.example.com/part-2" }], "uploadMode": "presigned" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The session does not exist. | Start a new session. |
OPERATION_FAILED | 409 | The session is not a multipart session. | Use a multipart session. |
Example
Section titled “Example”curl https://{domain}/api/files/upload/multipart/{sessionId}/parts -b cookies.txtAbort a multipart upload
Section titled “Abort a multipart upload”Aborts a multipart upload, releases the reserved quota, and marks the session as aborted.
DELETE /api/files/upload/multipart/{sessionId}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session identifier. |
Response
Section titled “Response”Returns data: null on success.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The session does not exist. | Start a new session. |
Example
Section titled “Example”curl -X DELETE https://{domain}/api/files/upload/multipart/{sessionId} \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtComplete an upload
Section titled “Complete an upload”Commits the uploaded object. The server verifies the object with a HEAD request, checks the size and ETag, merges multipart parts, then commits the metadata and quota in a single transaction.
POST /api/files/upload-complete
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session identifier. |
etag | string | No | The object ETag returned by the raw upload. Required for single-file sessions. |
parts | array | No | The part list { partNumber, etag } for pre-signed direct uploads. Ignored when the server recorded the parts. |
Response
Section titled “Response”{ "success": true, "data": { "file": { "id": "file-uuid", "name": "photo.jpg", "path": "/drive/photos", "size": 1048576, "createdAt": 1710000000000 } }, "timestamp": 1710000000000}Calling this endpoint again after success returns alreadyCompleted: true with the same result, which makes the completion idempotent.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The request body is invalid or an ETag is missing. | Provide the session and ETag. |
NOT_FOUND | 404 | The session does not exist. | Start a new session. |
OPERATION_FAILED | 409 | The session state prevents completion. | Start a new session. |
UPLOAD_SESSION_EXPIRED | 410 | The session expired. | Start a new session. |
OPERATION_FAILED | 422 | The object or parts fail verification. | Re-upload the file. |
Example
Section titled “Example”curl -X POST https://{domain}/api/files/upload-complete \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"sessionId":"session-uuid","etag":"\"abc123\""}'Compatible uploads
Section titled “Compatible uploads”PicGo and PicList upload to the compatible endpoints with a Bearer API key. The key must include the write permission. Both endpoints accept multipart/form-data or a raw body.
Upload with a compatible client
Section titled “Upload with a compatible client”POST /api/upload
POST /api/upload/upload
POST /api/compat/upload
Request headers
Section titled “Request headers”| Field | Type | Required | Description |
|---|---|---|---|
Authorization | string | Yes | Bearer {key_id}.{secret}. |
Content-Type | string | Depends | multipart/form-data, or the file MIME type for a raw body. |
For multipart/form-data, provide the file in the file field and an optional path field. For a raw body, set the file name with the X-File-Name header (or the legacy filename header) and an optional target path with the X-Path header.
Response
Section titled “Response”{ "success": true, "data": { "url": "https://{domain}/api/files/{fileId}/download", "fileId": "file-uuid", "path": "/uploads/2026/photo.jpg", "size": 1048576, "filename": "photo.jpg" }, "timestamp": 1710000000000}The path field honors the key’s upload path template, such as /uploads/{year}/{month}/. The final target must stay inside the key’s upload root.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | No valid API key. | Provide a Bearer key. |
INVALID_TOKEN | 401 | The API key is invalid, revoked, or expired. | Create a new key. |
FORBIDDEN | 403 | The key lacks the write permission, or the target is outside the upload root. | Grant write permission or adjust the path. |
QUOTA_EXCEEDED | 413 | The quota has run out. | Free up space or raise the quota. |
OPERATION_FAILED | 422 | The uploaded object fails verification. | Re-upload the file. |
Example
Section titled “Example”curl -X POST https://{domain}/api/upload \ -H "Authorization: Bearer pk_xxx.sk_yyy" \ -F "file=@photo.jpg" \ -F "path=/uploads/"Shares
Section titled “Shares”Share endpoints create, list, verify, download, preview, and revoke share links. Creating, listing, and revoking shares require a logged-in session. Reading a share, verifying its password, downloading, and previewing are public.
Create a share
Section titled “Create a share”Creates a share link for a file. Requires the share permission on the file.
POST /api/shares/
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
fileId | string | Yes | The file identifier. |
title | string | No | A display title. Defaults to the file name. |
password | string | No | A share password. The server stores only a hash. |
expiresIn | integer | No | The share lifetime in seconds, from 60 to 1 year. |
maxViews | integer | No | The maximum number of views. |
maxDownloads | integer | No | The maximum number of downloads. |
allowPreview | boolean | No | Allow in-page preview. Defaults to true. |
allowDownload | boolean | No | Allow downloads. Defaults to true. |
Response
Section titled “Response”Returns the share with its short id and public URL with status 201.
{ "success": true, "data": { "share": { "id": "abc123", "url": "https://{domain}/share/abc123", "expiresAt": null, "createdAt": 1710000000000, "passwordProtected": true, "allowPreview": true, "allowDownload": true } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | No logged-in session. | Log in first. |
VALIDATION_ERROR | 400 | A share parameter is invalid. | Correct the parameter and retry. |
FORBIDDEN | 403 | The caller lacks the share permission. | Check the permission rules. |
NOT_FOUND | 404 | The file does not exist. | Confirm the file identifier. |
Example
Section titled “Example”curl -X POST https://{domain}/api/shares/ \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"fileId":"file-uuid","password":"share-pass","expiresIn":604800}'List my shares
Section titled “List my shares”Returns the shares created by the current user with pagination.
GET /api/shares/?page={page}&limit={limit}&status={status}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 20, maximum 100. |
status | string | No | active, expired, or revoked. |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "id": "abc123", "title": "photo.jpg", "file": { "id": "file-uuid", "name": "photo.jpg", "path": "/drive/photos", "type": "file", "size": 1048576 }, "expiresAt": null, "viewCount": 3, "maxViews": null, "downloadCount": 1, "maxDownloads": null, "allowPreview": true, "allowDownload": true, "status": "active", "createdAt": 1710000000000 } ], "pagination": { "total": 1, "page": 1, "limit": 20, "pages": 1 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | No logged-in session. | Log in first. |
Example
Section titled “Example”curl "https://{domain}/api/shares/?status=active" -b cookies.txtGet share information
Section titled “Get share information”Returns public share information without requiring a login. When the share is password-protected, the response includes requiresPassword: true and no file data until the visitor verifies the password.
GET /api/shares/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The share id. |
Response
Section titled “Response”For a share without a password, or after password verification:
{ "success": true, "data": { "share": { "id": "abc123", "title": "photo.jpg", "creatorName": "alice", "file": { "id": "file-uuid", "name": "photo.jpg", "path": "/drive/photos", "type": "file", "size": 1048576, "mimeType": "image/jpeg" }, "allowPreview": true, "allowDownload": true, "expiresAt": null, "requiresPassword": false, "viewCount": 4, "maxViews": null, "downloadCount": 1, "maxDownloads": null } }, "timestamp": 1710000000000}For a password-protected share that is not yet verified, file, allowPreview, and allowDownload are null or false, and requiresPassword is true.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The share does not exist. | Confirm the share id. |
SHARE_REVOKED | 410 | The share link no longer works. | Ask the creator for a new link. |
SHARE_EXPIRED | 410 | The share expired. | Ask the creator for a new link. |
SHARE_LIMIT_REACHED | 410 | The share reached its view limit. | Ask the creator to raise the limit. |
Example
Section titled “Example”curl https://{domain}/api/shares/abc123Verify a share password
Section titled “Verify a share password”Verifies the share password. The password is sent in the request body, never in the URL. On success the endpoint sets a short-lived HttpOnly cookie, so subsequent requests to the share do not need the password again.
POST /api/shares/{id}/verify
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The share id. |
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
password | string | Yes | The share password. |
Response
Section titled “Response”{ "success": true, "data": { "authorized": true }, "timestamp": 1710000000000}The endpoint also sets a share_auth_{id} cookie that is valid for 15 minutes.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The share does not exist. | Confirm the share id. |
SHARE_EXPIRED | 410 | The share expired. | Ask the creator for a new link. |
INVALID_PASSWORD | 401 | The password is wrong. | Re-enter the password. |
Example
Section titled “Example”curl -X POST https://{domain}/api/shares/abc123/verify \ -H "Content-Type: application/json" \ -c cookies.txt \ -d '{"password":"share-pass"}'Get a share download link
Section titled “Get a share download link”Returns a single-use gateway download URL for the share. The download count increments only when the gateway consumes the token.
GET /api/shares/{id}/download
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The share id. |
Response
Section titled “Response”{ "success": true, "data": { "url": "https://{domain}/api/gateway/download/{token}", "expiresIn": 900 }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The share does not exist. | Confirm the share id. |
SHARE_REVOKED | 410 | The share is not active. | Ask the creator for a new link. |
SHARE_EXPIRED | 410 | The share expired. | Ask the creator for a new link. |
FORBIDDEN | 403 | The share does not allow downloads. | Ask the creator to enable downloads. |
INVALID_PASSWORD | 401 | The password is not verified. | Call the verify endpoint first. |
SHARE_LIMIT_REACHED | 410 | The share reached its download limit. | Ask the creator to raise the limit. |
Example
Section titled “Example”curl https://{domain}/api/shares/abc123/download -b cookies.txtPreview a shared file
Section titled “Preview a shared file”Streams the shared image directly with Content-Disposition: inline when the share allows preview. Returns binary image data, not JSON.
GET /api/shares/{id}/preview
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The share id. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The share or the file object does not exist. | Confirm the share id. |
SHARE_EXPIRED | 410 | The share is not active. | Ask the creator for a new link. |
FORBIDDEN | 403 | The share does not allow preview. | Ask the creator to enable preview. |
INVALID_PASSWORD | 401 | The password is not verified. | Call the verify endpoint first. |
Example
Section titled “Example”curl https://{domain}/api/shares/abc123/preview -o photo.jpgRevoke a share
Section titled “Revoke a share”Revokes a share. Only the share creator can revoke it.
DELETE /api/shares/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The share id. |
Response
Section titled “Response”Returns data: null on success.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | No logged-in session. | Log in first. |
NOT_FOUND | 404 | The share does not exist or belongs to another user. | Confirm the share id. |
Example
Section titled “Example”curl -X DELETE https://{domain}/api/shares/abc123 \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtUser endpoints read and update the current user’s settings, password, and email.
Get user settings
Section titled “Get user settings”Returns the profile, appearance, and quota of the current user.
GET /api/users/me/settings
Response
Section titled “Response”{ "success": true, "data": { "profile": { "username": "alice", "email": "alice@example.com", "emailVerified": true, "displayName": "Alice", "avatarUrl": null, "defaultPath": "/", "locale": "zh-CN", "role": "user", "createdAt": 1710000000000 }, "appearance": { "theme": "system", "accentColor": "#3B82F6", "enableBlur": true }, "quota": { "maxStorage": 10737418240, "usedStorage": 1048576, "maxFiles": 1000, "usedFiles": 3 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The user does not exist. | Log in with a valid account. |
Example
Section titled “Example”curl https://{domain}/api/users/me/settings -b cookies.txtUpdate user settings
Section titled “Update user settings”Updates the profile and appearance of the current user.
PUT /api/users/me/settings
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
displayName | string | No | The display name, at most 100 characters. Use null to clear. |
avatarUrl | string | No | An avatar URL, at most 1000 characters. Use null to clear. |
locale | string | No | zh-CN or en-US. |
theme | string | No | light, dark, or system. |
defaultPath | string | No | The default directory, starting with /. |
Response
Section titled “Response”{ "success": true, "data": { "message": "已保存" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A setting is invalid, or defaultPath does not start with /. | Correct the setting and retry. |
Example
Section titled “Example”curl -X PUT https://{domain}/api/users/me/settings \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"displayName":"Alice","theme":"dark","defaultPath":"/drive"}'Change the password
Section titled “Change the password”Changes the password of the current user. The change revokes all existing sessions, so the user must log in again.
PUT /api/users/me/password
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
oldPassword | string | Yes | The current password. |
newPassword | string | Yes | The new password, at least 8 characters. |
Response
Section titled “Response”{ "success": true, "data": { "message": "密码已修改,请重新登录" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The new password is shorter than 8 characters. | Choose a longer password. |
INVALID_PASSWORD | 401 | The current password is wrong. | Re-enter the old password. |
Example
Section titled “Example”curl -X PUT https://{domain}/api/users/me/password \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"oldPassword":"secret-pass","newPassword":"new-pass-123"}'Send an email verification code
Section titled “Send an email verification code”Sends a 6-digit verification code to the given email. The code is valid for 5 minutes. The site must enable email service.
POST /api/users/me/email/send-otp
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The email address to verify. |
Response
Section titled “Response”{ "success": true, "data": { "success": true, "expiresIn": 300 }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The email is invalid or already used by another account. | Use a different email. |
MAIL_ERROR | 500 | The email service failed to send the code. | Try again later or contact the administrator. |
Example
Section titled “Example”curl -X POST https://{domain}/api/users/me/email/send-otp \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"email":"new@example.com"}'Verify an email code
Section titled “Verify an email code”Verifies the 6-digit code and updates the user email. After 5 wrong attempts, the code stops working.
POST /api/users/me/email/verify-otp
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The email address to verify. |
code | string | Yes | The 6-digit code from the email. |
Response
Section titled “Response”{ "success": true, "data": { "success": true }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The code is invalid, expired, or has too many failed attempts. | Send a new code and retry. |
Example
Section titled “Example”curl -X POST https://{domain}/api/users/me/email/verify-otp \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"email":"new@example.com","code":"123456"}'API keys
Section titled “API keys”API key endpoints create, list, and revoke keys. Keys authenticate PicGo, PicList, scripts, and WebDAV clients. A user can have up to 20 active keys.
Create an API key
Section titled “Create an API key”Creates an API key. The full token is shown only once, so store it before you close the response. The server stores only a SHA-256 hash of the token.
POST /api/keys/
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A label for the key, at most 100 characters. |
permissions | array | Yes | read, write, or delete. At least one permission. |
protocols | array | Yes | webdav or api. At least one protocol. |
uploadPath | string | No | The upload root for writes. Defaults to /uploads. Normalized; the server rejects paths containing .. or ~. |
allowedIps | array | No | An IP whitelist. The server rejects requests from other IPs. |
expiresIn | integer | No | The key lifetime in seconds, at least 60. |
Response
Section titled “Response”Returns the key and ready-to-use client configuration with status 201.
{ "success": true, "data": { "key": { "id": "pk_abcdef123456", "keyId": "pk_abcdef123456", "secret": "sk_xyz789", "fullToken": "pk_abcdef123456.sk_xyz789", "name": "picgo", "permissions": ["write"], "protocols": ["api", "webdav"], "uploadPath": "/uploads", "createdAt": 1710000000000, "expiresAt": null }, "configs": { "bearer": { "url": "https://{domain}", "header": "Authorization: Bearer pk_abcdef123456.sk_xyz789" }, "webdav": { "url": "https://{domain}/webdav", "username": "pk_abcdef123456", "password": "sk_xyz789" } } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A request field is invalid. | Correct the field and retry. |
FORBIDDEN | 403 | The user already has 20 active keys, or the upload path is invalid. | Revoke an old key or fix the path. |
Example
Section titled “Example”curl -X POST https://{domain}/api/keys/ \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"name":"picgo","permissions":["write"],"protocols":["api"],"uploadPath":"/uploads"}'List API keys
Section titled “List API keys”Lists the keys of the current user without the secret.
GET /api/keys/
Response
Section titled “Response”{ "success": true, "data": { "keys": [ { "id": "key-uuid", "name": "picgo", "keyId": "pk_abcdef123456", "permissions": ["write"], "protocols": ["api"], "uploadPath": "/uploads", "lastUsedAt": null, "expiresAt": null, "createdAt": 1710000000000, "status": "active" } ] }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/keys/ -b cookies.txtGet key permission rules
Section titled “Get key permission rules”Returns the path rules that apply to the current user’s keys. Use this endpoint for display and debugging.
GET /api/keys/rules
Response
Section titled “Response”{ "success": true, "data": { "rules": [] }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/keys/rules -b cookies.txtRevoke an API key
Section titled “Revoke an API key”Revokes a key so it can no longer authenticate.
DELETE /api/keys/{id}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The key identifier. |
Response
Section titled “Response”Returns data: null on success.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
NOT_FOUND | 404 | The key does not exist or belongs to another user. | Confirm the key identifier. |
Example
Section titled “Example”curl -X DELETE https://{domain}/api/keys/{id} \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtAdmin endpoints manage users, shares, files, logs, settings, announcements, storage providers, mounts, and permission rules. All of them require an administrator session.
Get the dashboard
Section titled “Get the dashboard”Returns aggregate statistics, recent activity, and the request count for the last 24 hours.
GET /api/admin/dashboard
Response
Section titled “Response”{ "success": true, "data": { "stats": { "users": 12, "files": 345, "storage": [{ "providerId": "provider-uuid", "name": "R2", "usedSpace": 10485760, "fileCount": 300 }] }, "requests24h": 1200, "recentActivity": [{ "action": "upload", "path": "/drive/a.txt", "userId": "user-uuid", "createdAt": 1710000000000 }] }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/admin/dashboard -b cookies.txtGet statistics
Section titled “Get statistics”Returns user, file, and storage statistics.
GET /api/admin/stats
Response
Section titled “Response”{ "success": true, "data": { "users": 12, "files": 345, "storage": [{ "providerId": "provider-uuid", "name": "R2", "usedSpace": 10485760, "fileCount": 300 }], "recentActivity": [] }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/admin/stats -b cookies.txtManage users
Section titled “Manage users”Lists, updates, and deletes users.
GET /api/admin/users?page={page}&limit={limit}&role={role}&status={status}&search={search}
PUT /api/admin/users/{id}
DELETE /api/admin/users/{id}
List query parameters
Section titled “List query parameters”| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 20, maximum 100. |
role | string | No | Filter by role. |
status | string | No | Filter by status. |
search | string | No | A keyword to match users. |
Update request body
Section titled “Update request body”| Field | Type | Required | Description |
|---|---|---|---|
role | string | No | admin, user, or guest. |
status | string | No | active, disabled, or banned. Disabling or banning revokes the user sessions. |
defaultPath | string | No | The default directory, starting with /. |
maxStorage | integer | No | The storage quota in bytes. |
maxFiles | integer | No | The file-count quota. |
List response
Section titled “List response”{ "success": true, "data": { "users": [{ "id": "user-uuid", "username": "alice", "role": "user", "status": "active", "quota": {} }], "pagination": { "total": 12, "page": 1, "limit": 20, "pages": 1 } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | A user parameter is invalid, or the request tries to delete the own account. | Correct the parameter. |
NOT_FOUND | 404 | The user does not exist. | Confirm the user id. |
Example
Section titled “Example”curl "https://{domain}/api/admin/users?role=user&limit=20" -b cookies.txt
curl -X PUT https://{domain}/api/admin/users/{id} \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"role":"admin","status":"active"}'Manage shares
Section titled “Manage shares”Lists all shares and revokes any share.
GET /api/admin/shares?page={page}&limit={limit}&status={status}
DELETE /api/admin/shares/{id}
List query parameters
Section titled “List query parameters”| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 20, maximum 100. |
status | string | No | Filter by share status. |
List response
Section titled “List response”{ "success": true, "data": { "items": [{ "id": "abc123", "title": "photo.jpg", "creatorId": "user-uuid", "status": "active" }], "pagination": { "total": 5, "page": 1, "limit": 20, "pages": 1 } }, "timestamp": 1710000000000}Example
Section titled “Example”curl "https://{domain}/api/admin/shares?status=active" -b cookies.txt
curl -X DELETE https://{domain}/api/admin/shares/abc123 \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtList all files
Section titled “List all files”Searches every file across all mounts.
GET /api/admin/files?page={page}&limit={limit}&search={search}
List query parameters
Section titled “List query parameters”| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 20, maximum 100. |
search | string | No | A keyword to match file names. |
Response
Section titled “Response”{ "success": true, "data": { "items": [{ "id": "file-uuid", "name": "photo.jpg", "path": "/drive/photos", "type": "file", "size": 1048576 }], "pagination": { "total": 345, "page": 1, "limit": 20, "pages": 18 } }, "timestamp": 1710000000000}Example
Section titled “Example”curl "https://{domain}/api/admin/files?search=photo" -b cookies.txtRead access logs
Section titled “Read access logs”Returns access logs with pagination and filtering.
GET /api/admin/logs?page={page}&limit={limit}&userId={userId}&action={action}&search={search}&from={from}&to={to}
List query parameters
Section titled “List query parameters”| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | The page number. Defaults to 1. |
limit | integer | No | Items per page. Defaults to 50, maximum 200. |
userId | string | No | Filter by user. |
action | string | No | Filter by action, such as upload or download. |
search | string | No | A keyword to match log content. |
from | integer | No | Start time in milliseconds. |
to | integer | No | End time in milliseconds. |
Response
Section titled “Response”{ "success": true, "data": { "logs": [{ "id": "log-uuid", "userId": "user-uuid", "action": "upload", "path": "/drive/a.txt", "bytesTransferred": 1024, "statusCode": 200, "createdAt": 1710000000000 }], "pagination": { "total": 5000, "page": 1, "limit": 50, "pages": 100 } }, "timestamp": 1710000000000}Example
Section titled “Example”curl "https://{domain}/api/admin/logs?action=upload&limit=50" -b cookies.txtManage system settings
Section titled “Manage system settings”Reads and updates the global site settings, including registration, email, rate limits, and Turnstile.
GET /api/admin/settings
PATCH /api/admin/settings
Update request body
Section titled “Update request body”All fields are optional.
| Field | Type | Required | Description |
|---|---|---|---|
siteTitle | string | No | The site title. |
siteLogo | string | No | The site logo URL. |
siteFavicon | string | No | The favicon URL. |
allowRegistration | boolean | No | Allow new user registration. |
allowGuestAccess | boolean | No | Allow guest access. |
requireEmailVerification | boolean | No | Require email verification on registration. |
enableTurnstile | boolean | No | Enable Cloudflare Turnstile. |
turnstileSiteKey | string | No | The Turnstile site key. |
rateLimitEnabled | boolean | No | Enable rate limiting. |
rateLimitRequestsPerMinute | integer | No | Requests per minute, 1 to 10000. |
smtpHost | string | No | The SMTP host. |
smtpPort | integer | No | The SMTP port. |
smtpSecure | boolean | No | Use a secure SMTP connection. |
smtpUser | string | No | The SMTP user. |
smtpPassword | string | No | The SMTP password. Pass "******" or an empty string to keep the current password. |
smtpFromName | string | No | The sender name. |
smtpFromEmail | string | No | The sender email. |
emailEnabled | boolean | No | Enable email service. |
Example
Section titled “Example”curl -X PATCH https://{domain}/api/admin/settings \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"siteTitle":"My Picumet","rateLimitRequestsPerMinute":60}'Send a test email
Section titled “Send a test email”Sends a test email through the configured SMTP service.
POST /api/admin/settings/test-email
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | The recipient email address. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The email is invalid or SMTP is not configured. | Configure SMTP first. |
MAIL_ERROR | 500 | The email service failed. | Check the SMTP configuration. |
Example
Section titled “Example”curl -X POST https://{domain}/api/admin/settings/test-email \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"to":"admin@example.com"}'Manage announcements
Section titled “Manage announcements”Lists, creates, updates, and deletes announcements.
GET /api/admin/announcements
POST /api/admin/announcements
PUT /api/admin/announcements/{id}
DELETE /api/admin/announcements/{id}
Create request body
Section titled “Create request body”| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | The announcement title, at most 200 characters. |
content | string | Yes | The announcement content, at most 5000 characters. |
level | string | No | info, warning, or danger. |
expiresIn | integer | No | The announcement lifetime in seconds, at least 60. |
Example
Section titled “Example”curl -X POST https://{domain}/api/admin/announcements \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"title":"Maintenance","content":"Downtime on Saturday","level":"warning"}'Manage storage providers
Section titled “Manage storage providers”Lists, creates, updates, tests, and deletes storage providers. The server stores credentials encrypted.
GET /api/admin/storage/providers
POST /api/admin/storage/providers
PUT /api/admin/storage/providers/{id}
POST /api/admin/storage/providers/{id}/test
DELETE /api/admin/storage/providers/{id}
Create request body
Section titled “Create request body”| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | A label for the provider. |
type | string | Yes | r2, s3, or oracle. |
endpoint | string | No | The S3 endpoint. Leave empty for a bound R2 provider. Public http(s) addresses only. |
region | string | No | The region. Defaults to auto for R2. |
bucket | string | Yes | The bucket name. |
accessKeyId | string | No | The access key. Leave empty for a bound R2 provider. |
secretAccessKey | string | No | The secret key. Leave empty for a bound R2 provider. |
publicDomain | string | No | A public CDN domain for direct URLs. |
uploadDomain | string | No | A custom upload domain. |
pathPrefix | string | No | A prefix applied to object keys. |
Test response
Section titled “Test response”{ "success": true, "data": { "connected": true, "message": "ok" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The endpoint fails SSRF checks or a field is invalid. | Use a public endpoint or correct the field. |
NOT_FOUND | 404 | The provider does not exist. | Confirm the provider id. |
OPERATION_FAILED | 409 | The provider still has mounts. | Delete the mounts first. |
Example
Section titled “Example”curl -X POST https://{domain}/api/admin/storage/providers \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"name":"R2","type":"r2","bucket":"my-bucket"}'Manage mounts
Section titled “Manage mounts”Lists, creates, updates, and deletes mount points that bind a provider to a virtual path.
GET /api/admin/mounts
POST /api/admin/mounts
PUT /api/admin/mounts/{id}
DELETE /api/admin/mounts/{id}
Create request body
Section titled “Create request body”| Field | Type | Required | Description |
|---|---|---|---|
providerId | string | Yes | The storage provider id. |
mountPath | string | Yes | The virtual path, such as /drive. |
name | string | Yes | A display name. |
sortBy | string | No | The default sort field. |
sortOrder | string | No | asc or desc. |
priority | integer | No | The mount priority. Higher values win for overlapping paths. |
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The provider does not exist or a field is invalid. | Correct the input. |
OPERATION_FAILED | 409 | The mount still contains files. | Delete the files first. |
Example
Section titled “Example”curl -X POST https://{domain}/api/admin/mounts \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"providerId":"provider-uuid","mountPath":"/drive","name":"Drive"}'Manage permission rules
Section titled “Manage permission rules”Lists, creates, updates, and deletes path-based permission rules. Each rule targets exactly one subject: a role, a user, or an API key.
GET /api/admin/rules?page={page}&limit={limit}
POST /api/admin/rules
PUT /api/admin/rules/{id}
DELETE /api/admin/rules/{id}
Create request body
Section titled “Create request body”| Field | Type | Required | Description |
|---|---|---|---|
pathPattern | string | Yes | The path pattern, such as /public/**. |
effect | string | Yes | allow or deny. |
mountId | string | No | The mount this rule applies to. Empty means all mounts. |
role | string | No | The role subject. Mutually exclusive with userId and apiKeyId. |
userId | string | No | The user subject. Mutually exclusive with role and apiKeyId. |
apiKeyId | string | No | The API key subject. Mutually exclusive with role and userId. |
permissions | array | No | The permissions the rule grants, such as ["read","write"]. |
requirePassword | boolean | No | Require a password on the matched paths. |
password | string | No | The plaintext password. The server stores only a hash. |
allowedIps | array | No | An IP whitelist for the rule. |
priority | integer | No | The rule priority. |
The list response masks passwordHash values.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The rule must specify exactly one of role, userId, or apiKeyId. | Set exactly one subject. |
Example
Section titled “Example”curl -X POST https://{domain}/api/admin/rules \ -H "Content-Type: application/json" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -d '{"pathPattern":"/public/**","effect":"allow","role":"guest","permissions":["read"]}'Free mode
Section titled “Free mode”Free-mode endpoints let an anonymous visitor use their own object-storage credentials in a temporary session. The server encrypts credentials and stores them in KV for a short TTL. The session endpoints require the fm_token cookie, and write operations require a session-level CSRF token.
Initialize a free-mode session
Section titled “Initialize a free-mode session”Validates the storage endpoint, tests the connection, and starts a temporary session. Sets the fm_token cookie.
POST /api/free-mode/init
Request body
Section titled “Request body”| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | r2, s3, or oracle. |
endpoint | string | Yes | The S3 endpoint. Public http(s) addresses only; the server rejects private or local addresses. |
region | string | No | The region. |
bucket | string | Yes | The bucket name. |
accessKeyId | string | Yes | The access key. |
secretAccessKey | string | Yes | The secret key. |
sessionHours | integer | No | The session lifetime in hours, 1 to 8. Defaults to 1. |
Response
Section titled “Response”Returns the session user, expiry, and a session-level CSRF token with status 201.
{ "success": true, "data": { "user": { "id": "user-uuid", "username": "fm_ab12cd34", "role": "user", "defaultPath": "/" }, "expiresAt": 1710003600000, "sessionHours": 1, "provider": { "type": "s3", "bucket": "my-bucket" }, "csrfToken": "32-char-random-string" }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | The endpoint is private or invalid, or a field is malformed. | Use a public endpoint and valid credentials. |
OPERATION_FAILED | 400 | The storage connection test failed. | Check the credentials and endpoint. |
Example
Section titled “Example”curl -X POST https://{domain}/api/free-mode/init \ -H "Content-Type: application/json" \ -c cookies.txt \ -d '{"type":"s3","endpoint":"https://s3.example.com","bucket":"my-bucket","accessKeyId":"AK","secretAccessKey":"SK","sessionHours":1}'List free-mode files
Section titled “List free-mode files”Lists the objects in the free-mode session root.
GET /api/free-mode/files?path={path}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
path | string | No | The directory prefix to list. Must stay inside the session root. |
Response
Section titled “Response”{ "success": true, "data": { "items": [ { "key": "photo.jpg", "name": "photo.jpg", "path": "/photo.jpg", "type": "file", "size": 1048576, "etag": "\"abc123\"" } ], "mount": { "id": "free", "name": "自由模式", "mountPath": "/", "sortBy": "name", "sortOrder": "asc" } }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | The session is missing or expired. | Initialize a new session. |
FORBIDDEN | 403 | The path is outside the session root. | Use a path inside the root. |
Example
Section titled “Example”curl "https://{domain}/api/free-mode/files" -b cookies.txtUpload to free mode
Section titled “Upload to free mode”Uploads a file to the free-mode session. The file must be 1 GB or smaller.
POST /api/free-mode/upload?path={path}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
path | string | No | The target directory prefix. |
Request headers
Section titled “Request headers”| Field | Type | Required | Description |
|---|---|---|---|
X-CSRF-Token | string | Yes | The session CSRF token from the init response. |
X-File-Name | string | Only for raw bodies | The file name, used when the body is not multipart/form-data. |
Use multipart/form-data with a file field, or send the raw file bytes with the X-File-Name header.
Response
Section titled “Response”Returns the object key and size with status 201.
{ "success": true, "data": { "key": "photo.jpg", "size": 1048576 }, "timestamp": 1710000000000}Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | The session is missing or expired. | Initialize a new session. |
INVALID_CSRF | 403 | The session CSRF token is wrong. | Use the token from the init response. |
VALIDATION_ERROR | 400 | The file name or path is invalid. | Correct the input. |
PAYLOAD_TOO_LARGE | 413 | The file exceeds 1 GB. | Use a smaller file. |
FORBIDDEN | 403 | The target key is outside the session root. | Use a path inside the root. |
Example
Section titled “Example”curl -X POST "https://{domain}/api/free-mode/upload" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txt \ -F "file=@photo.jpg"Delete a free-mode object
Section titled “Delete a free-mode object”Deletes an object from the free-mode session.
DELETE /api/free-mode/object?key={key}
Query parameters
Section titled “Query parameters”| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | The object key. Must stay inside the session root and contain no .., ~, control characters, or backslashes. |
Response
Section titled “Response”Returns data: null on success.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
UNAUTHORIZED | 401 | The session is missing or expired. | Initialize a new session. |
VALIDATION_ERROR | 400 | The key is missing, too long, or contains illegal characters. | Correct the key. |
FORBIDDEN | 403 | The key is outside the session root. | Use a key inside the root. |
Example
Section titled “Example”curl -X DELETE "https://{domain}/api/free-mode/object?key=photo.jpg" \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtEnd a free-mode session
Section titled “End a free-mode session”Ends the free-mode session and clears the fm_token cookie.
POST /api/free-mode/logout
Response
Section titled “Response”Returns data: null on success.
Example
Section titled “Example”curl -X POST https://{domain}/api/free-mode/logout \ -H "X-CSRF-Token: {csrf_token}" \ -b cookies.txtWebDAV
Section titled “WebDAV”The WebDAV service exposes the file store to standard WebDAV clients. Every request authenticates with Basic auth using the API key pair: username {key_id}, password {secret}. The base URL is https://{domain}/webdav. All methods enforce path-level permissions, and write targets must stay inside the key’s upload root.
WebDAV methods
Section titled “WebDAV methods”| Method | Description | Permission |
|---|---|---|
OPTIONS | Announces DAV capabilities (DAV: 1,2). | None |
PROPFIND | Lists a directory as an XML multistatus response. | read |
MKCOL | Creates a folder. | write, inside the upload root |
PUT | Uploads a file with a streaming body. | write, inside the upload root |
GET / HEAD | Downloads a file or reads its information. | read |
DELETE | Deletes a file or folder. | delete |
MOVE | Moves or renames an entry. Uses the move Saga. | delete on source, write on target |
Example: list a directory
Section titled “Example: list a directory”curl -X PROPFIND https://{domain}/webdav/ \ -u "pk_xxx:sk_yyy" \ -H "Depth: 1"Example: upload a file
Section titled “Example: upload a file”curl -X PUT https://{domain}/webdav/uploads/photo.jpg \ -u "pk_xxx:sk_yyy" \ -H "Content-Type: image/jpeg" \ --data-binary @photo.jpgExample: move an entry
Section titled “Example: move an entry”curl -X MOVE https://{domain}/webdav/uploads/photo.jpg \ -u "pk_xxx:sk_yyy" \ -H "Destination: https://{domain}/webdav/uploads/renamed.jpg"Download gateway
Section titled “Download gateway”The gateway streams an object after consuming a single-use download token. Tokens stay valid for 15 minutes, and the gateway consumes each token atomically, so concurrent requests cannot reuse a token.
Download through the gateway
Section titled “Download through the gateway”GET /api/gateway/download/{token}
Path parameters
Section titled “Path parameters”| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The single-use download token from a download or share endpoint. |
The gateway streams the object with the stored content type and an appropriate Content-Disposition. For password-protected files, the token must carry password verification. For shares, the gateway increments the download count once.
Errors
Section titled “Errors”| Error Code | HTTP Status | Cause | Recommended Action |
|---|---|---|---|
INVALID_TOKEN | 401 | The token is invalid or expired. | Generate a new download link. |
PASSWORD_REQUIRED | 403 | The file is password-protected and the token is not verified. | Verify the file password first. |
NOT_FOUND | 404 | The file or object no longer exists. | Confirm the file still exists. |
SHARE_LIMIT_REACHED | 410 | The share reached its download limit. | Ask the creator to raise the limit. |
Example
Section titled “Example”curl -L "https://{domain}/api/gateway/download/{token}" -o photo.jpgPublic endpoints
Section titled “Public endpoints”Public endpoints require no authentication.
Get public settings
Section titled “Get public settings”Returns site-wide settings for the landing page and login screen.
GET /api/public/settings
Response
Section titled “Response”{ "success": true, "data": { "siteTitle": "Picumet", "siteLogo": null, "siteFavicon": null, "allowGuestAccess": false, "allowRegistration": true, "requireEmailVerification": false }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/public/settingsList active announcements
Section titled “List active announcements”Returns the currently active announcements.
GET /api/public/announcements
Response
Section titled “Response”{ "success": true, "data": { "items": [{ "id": "announcement-uuid", "title": "Maintenance", "content": "Downtime on Saturday", "level": "warning" }] }, "timestamp": 1710000000000}Example
Section titled “Example”curl https://{domain}/api/public/announcementsHealth checks
Section titled “Health checks”Returns service health. The liveness probe always reports ok. The readiness probe reports 503 with ready: false until the database seed completes.
GET /api/public/health
GET /api/public/health/live
GET /api/public/health/ready
Response
Section titled “Response”{ "service": "picumet-api", "status": "ok", "ready": true, "detail": "seeded" }Example
Section titled “Example”curl https://{domain}/api/public/health/readyServe files from public paths
Section titled “Serve files from public paths”The API serves files directly from their public virtual path, for example GET https://{domain}/drive/photos/photo.jpg. This route runs after all API and WebDAV routes, so it never shadows them.
Files on a public mount serve with no authentication. Files on a private mount require a logged-in session with download permission. Password-protected files return 403 PASSWORD_REQUIRED. Paths that are not mounted, or that contain .., return 404.
Example
Section titled “Example”curl "https://{domain}/drive/photos/photo.jpg" -o photo.jpgWhat’s next
Section titled “What’s next”- System architecture for the service design behind these endpoints.
- Development guide for running and testing the Workers codebase.
- Deployment guide for configuring bindings, secrets, and domains.
- Frontend guide for the pages that consume this API.
- Project overview and progress tracking.