Admin API
The following paths are relative to /api/v1. Every endpoint on this page requires administrator privileges except the storage OAuth provider callback /admin/policies/storage-authorization/callback.
This page keeps the most important admin endpoint groups. For usage-oriented admin-console guidance, see Admin Console.
Most admin list endpoints already use offset pagination:
/admin/policies/admin/policy-groups/admin/remote-nodes/admin/users/admin/teams/admin/teams/{id}/members/admin/shares/admin/tasks/admin/files/admin/file-blobs/admin/config/admin/locks/admin/audit-logs
Default ordering varies by DTO. Common defaults:
- users, teams, policies, policy groups, remote nodes, shares, audit logs:
created_at desc - background tasks:
updated_at desc - locks:
id asc - team members:
role asc
Overview
Section titled “Overview”| Method | Path | Description |
|---|---|---|
GET | /admin/overview | Read aggregated admin dashboard data |
GET | /admin/system-info | Read authenticated version and build time |
The overview response includes user, file, blob, share, audit, and task summaries plus recent activity. Query parameters include days, timezone, and event_limit.
GET /admin/system-info returns { "version": "...", "build_time": "..." }. Build fingerprints are exposed only through this authenticated admin route; anonymous /health reports service status without version or build details.
Storage policies
Section titled “Storage policies”| Method | Path | Description |
|---|---|---|
GET | /admin/policies | List storage policies |
POST | /admin/policies | Create storage policy |
GET | /admin/policies/{id} | Read policy details |
GET | /admin/policies/{id}/capacity | Read policy capacity observation |
PATCH | /admin/policies/{id} | Update policy |
DELETE | /admin/policies/{id} | Delete policy |
GET | /admin/policies/storage-drivers | List storage connector descriptors |
GET | /admin/policies/storage-credential-providers | List storage OAuth credential providers |
POST | /admin/policies/{id}/test | Test saved policy |
POST | /admin/policies/{id}/action | Execute a storage action for a saved policy |
POST | /admin/policies/{id}/promote-s3-driver | Promote a generic S3-compatible policy to a supported specialized driver |
POST | /admin/policies/{id}/storage-authorization/start | Start storage OAuth authorization for a policy |
GET | /admin/policies/{id}/storage-credentials | List stored OAuth credentials for a policy |
POST | /admin/policies/{id}/storage-credentials/{provider}/validate | Validate a stored OAuth credential |
GET | /admin/policies/storage-authorization/callback | Storage OAuth provider callback entry; does not require an admin JWT and redirects back to the admin UI |
POST | /admin/policies/test | Test connection with draft parameters |
POST | /admin/policies/action | Execute a storage action with draft policy parameters |
Create example (connector-owned connection):
{ "name": "archive-s3", "connection": { "connector_config": { "format_version": 1, "connector_id": "asterdrive.storage.s3", "schema_version": 1, "values": { "endpoint": "https://s3.example.com", "bucket": "archive", "base_path": "asterdrive/" } }, "credential": { "mode": "static", "values": { "access_key": "AKIA...", "secret_key": "..." } }, "behavior": {} }, "max_file_size": 10737418240, "chunk_size": 10485760, "is_default": false}Current notes:
driver_typecurrently supportslocal,s3,alibaba_oss,huawei_obs,sftp,azure_blob,tencent_cos,remote, andone_driveGET /admin/policies/storage-driversreturnsStorageConnectorDescriptorentries. The frontend should use descriptorcapabilities,fields,upload_workflows,actions, andcredential_modeto decide forms, connection tests, upload/download strategies, and action affordances instead of maintaining a hard-coded driver capability matrix.- create and update both honor request
chunk_size optionscarries policy-level behavior:- S3-compatible / Alibaba OSS / Azure Blob / Tencent COS object-storage connectors use
object_storage_upload_strategy/object_storage_download_strategyfor transfer strategy. Legacys3_upload_strategy/s3_download_strategyJSON remains accepted as a compatibility alias. - The Tencent COS descriptor declares
custom_download_base_urland exposes the connector-owned optionaldownload_base_urlfield for an HTTPS browser-download delivery root. The runtime driver builds the final object path and COS Q-Sign against that host; backend I/O, uploads, cleanup, CORS, and bucket administration continue to use the official COS endpoint. - Native Alibaba OSS fields: public
endpoint, optionaloss_server_side_endpoint,oss_region, andoss_use_cname. Backend I/O prefers the server-side endpoint, while presigned URLs always use the public endpoint. CNAME mode accepts a custom domain; normal mode accepts analiyuncs.comOSS endpoint. - Remote upload and download strategies through
remote_upload_strategy/remote_download_strategy - local
content_dedup - generic S3 path-style addressing through
s3_path_style(defaults totrue) - S3 SigV4 signing region through
s3_region. This optional string is trimmed; an empty or whitespace-only value normalizes to unset, with runtime falling back toauto. A non-empty value must contain 1–128 printable ASCII characters and must not contain whitespace or/; invalid values are rejected asBadRequest(HTTP 400 with response codebad_request). Custom S3-compatible endpoints that require a fixed region should use the provider-specified value. Draft connection tests and the saved S3 runtime driver use the same region. - S3 connect / read / operation timeouts
- Huawei OBS fields: regional or custom-domain
endpoint,bucket, optionalobs_region, andobs_addressing_mode; OBS uses marker-based ListObjects pagination and the same object-storage upload/download strategies as other S3-shaped connectors - core-owned storage-native thumbnails / image previews with
storage_native_thumbnail_enabledandstorage_native_thumbnail_extensions; connector descriptors only advertise support - core-owned storage-native media metadata with
storage_native_media_metadata_enabledandstorage_native_media_metadata_extensions; connector descriptors only advertise support - OneDrive location options:
onedrive_account_mode,onedrive_tenant,onedrive_site_id,onedrive_drive_id,onedrive_group_id, andonedrive_root_item_id - OneDrive large-upload strategy through
provider_resumable_upload_strategy:server_relay(default) orfrontend_direct - OneDrive download strategy through
provider_download_strategy:server_relay(default) orfrontend_direct - OneDrive download filename semantics through
provider_download_filename_mode:provider_native(default) orstrict_current - SFTP host key pinning:
sftp_host_key_fingerprint
- S3-compatible / Alibaba OSS / Azure Blob / Tencent COS object-storage connectors use
application_config.microsoft_graphstores OneDrive / Microsoft Graph app settings. Client secrets are stored encrypted; API responses expose onlyclient_secret_configured.driver_type = "azure_blob"uses Azure Block Blob capabilities. Presigned browser upload uses SAS URLs and requires the client to sendx-ms-blob-type: BlockBlob.driver_type = "one_drive"uses Microsoft Graph OAuth credentials. Save the policy andapplication_config.microsoft_graphbefore starting authorization.driver_type = "sftp"uses SSH username / password credentials to connect to an SFTP server. Endpoint supportssftp://host:port, barehost, andhost:port; the remote root belongs inbase_path. Unknown or mismatched SSH host keys are rejected asStorageErrorKind::Preconditionwith diagnostics that include actual / expected fingerprints; the confirmed fingerprint is stored inoptions.sftp_host_key_fingerprint.driver_type = "tencent_cos"uses the S3-compatible object path for normal reads and writes and validates Tencent COS endpoint shape. Optionaldownload_base_urlaccepts an HTTPS delivery domain with a controlled path prefix and rejects userinfo, non-default ports, query, fragment, backslashes, and traversal; the connector can also expose COS CI storage-native thumbnail / image-preview / media-metadata capabilities when the policy opts indriver_type = "alibaba_oss"reuses AWS S3 SDK object, streaming, and multipart orchestration but applies nativeOSS4-HMAC-SHA256header/query signing; normal requests and generated presigning are validated separatelydriver_type = "huawei_obs"reuses AWS S3 SDK object, streaming, and multipart serialization while applying native Huawei OBS signing; virtual-hosted and custom-domain addressing, marker-based listing, normal requests, and generated presigning are validated separately- built-in Local, S3-compatible, Alibaba OSS, Huawei OBS, SFTP, Azure Blob, OneDrive, and Remote drivers do not expose storage-native thumbnail, image-preview, or media-metadata capabilities
- legacy
{"presigned_upload":true}remains compatible with object-storage presigned upload allowed_typescan be managed through REST- Creating a
driver_type = "remote"policy requires bothremote_node_idandremote_storage_target_key. The target must belong to that node’s current binding, have nolast_error, and satisfyapplied_revision >= desired_revision. - After a node is selected, the policy create/edit UI loads its target list and driver descriptors. An admin can quick-create a target in the same flow, after which the new target is selected automatically. Fields and capabilities remain backend-descriptor driven.
- Every remote policy requires an explicit
remote_storage_target_key. Policies created by older builds without one must be edited and saved with a target before they can read, write, or report capacity. PATCHcannot changedriver_typePOST /admin/policies/{id}/promote-s3-drivercurrently supports promoting a generics3policy totencent_cos. The body must include the target driver and current endpoint / bucket, for example{ "target_driver_type": "tencent_cos", "endpoint": "https://bucket-1250000000.cos.ap-guangzhou.myqcloud.com", "bucket": "bucket-1250000000" }. Promotion is rejected unless the bucket stays unchanged, there are no active upload sessions for the policy, and the target driver validates the endpoint / bucket combination.GET /admin/policiessupportslimit,offset,sort_by,sort_orderGET /admin/policies/{id}/capacityreturnsStoragePolicyCapacityInfo; local returns filesystem capacity, S3-compatible and Azure Blob are explicitly unsupported, OneDrive reads Microsoft Graph drive quota, and remote forwards follower capacity statusDELETE /admin/policies/{id}?force=trueonly cleans upload sessions that still reference the policy. Existing blobs or policy-group references still block deletion. Deleting the last default policy returns the system toneeds_storage; if temp objects or multipart uploads need delayed cleanup, astorage_policy_temp_cleanuptask is created.
Storage connection tests
Section titled “Storage connection tests”POST /admin/policies/{id}/test and POST /admin/policies/test return an ordinary empty success response on success:
{ "code": "success", "msg": "", "data": {}}Failed connection tests no longer return a StoragePolicyProbeResult success payload. They use the standard error response and expose redacted diagnostics through error.diagnostic:
{ "code": "storage.auth_failed", "msg": "storage authentication failed", "error": { "retryable": false, "diagnostic": { "kind": "auth", "message": "credentials were rejected by the storage provider" } }}Draft test requests support optional policy_id. While editing a saved policy, blank sensitive fields such as access_key or secret_key can be filled from the saved policy by S3-compatible, SFTP, Azure Blob, and Tencent COS connectors. Unsaved new policies must still provide complete credentials.
Storage OAuth Credentials
Section titled “Storage OAuth Credentials”These endpoints currently mainly serve the OneDrive / Microsoft Graph connector:
GET /admin/policies/storage-credential-providerslists providers.microsoft_graphis currently supported;google_driveis reserved withsupported = false.- Creating or updating a OneDrive policy first saves Microsoft Graph app settings through
application_config.microsoft_graph; client secrets are encrypted at rest. POST /admin/policies/{id}/storage-authorization/startonly needs the provider; the backend reuses saved application config to start authorization.- After successful authorization, the callback writes
storage_policy_credentialsand redirects to/admin/policies?storage_authorization=success&policy_id=.... The callback does not require an admin JWT because Microsoft Graph and similar providers return to it through the browser. GET /admin/policies/{id}/storage-credentialsreturns credential status, tenant, account label, scopes, expiry, and refresh timestamps, but never access or refresh tokens.POST /admin/policies/{id}/storage-credentials/{provider}/validatevalidates the stored credential and updates status toauthorized,reauth_required,permission_denied, orinvalid.
Start authorization example:
POST /api/v1/admin/policies/12/storage-authorization/start{ "provider": "microsoft_graph"}The returned authorization_url is meant for browser navigation:
{ "code": "success", "msg": "", "data": { "authorization_url": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?...", "expires_in": 300, "provider": "microsoft_graph", "microsoft_graph": { "cloud": "global", "tenant": "common", "client_id": "00000000-0000-0000-0000-000000000000", "client_secret_configured": true, "scopes": ["offline_access", "Files.ReadWrite.All", "Sites.ReadWrite.All"] } }}Storage policy actions
Section titled “Storage policy actions”Storage policy actions are the unified entry point for optional management capabilities exposed by storage drivers. Default built-in capabilities should extend the StoragePolicyActionType enum instead of adding provider-specific HTTP routes. Future plugin capabilities may expose their own schema route for parameter discovery, but execution should still stay action-oriented where possible.
Current actions:
| action | Supported driver | Mutates remote state | Description |
|---|---|---|---|
configure_tencent_cos_cors | tencent_cos | yes | Configure Tencent COS bucket CORS from public_site_url |
Saved policy request:
POST /api/v1/admin/policies/12/action{ "action": "configure_tencent_cos_cors"}Draft policy request:
POST /api/v1/admin/policies/action{ "action": "configure_tencent_cos_cors", "policy_id": 12, "driver_type": "tencent_cos", "endpoint": "https://bucket-1250000000.cos.ap-guangzhou.myqcloud.com", "bucket": "bucket-1250000000", "access_key": "AKID...", "secret_key": "...", "base_path": "prod/"}configure_tencent_cos_cors behavior:
- request bodies do not accept
allowed_originorallowed_origins - draft request connection fields are flat fields, not nested under a
policyobject policy_idis optional and is only used for draft actions while editing a saved policy; ifaccess_keyorsecret_keyis blank, the backend fills that blank credential field from the saved policy- without
policy_id, draft actions must carry complete credentials themselves; this covers unsaved new policies and purely transient parameter tests - the backend reads all origins from runtime config
public_site_urland writes them as multipleAllowedOriginentries in one COS CORS rule - if
public_site_urlis empty, the action returnspolicy.action_parameter_required - if the policy is not
tencent_cos, the action returnspolicy.action_unsupported - AsterDrive uses the stable rule id
asterdrive-presigned-access - Tencent COS does not provide an atomic append-CORS-rule API; AsterDrive reads current rules with
GET Bucket cors, preserves unrelated rules, replaces the rule with the same ID, and writes the full document back withPUT Bucket cors PUT Bucket corsrequiresContent-MD5; the server calculates the MD5 of the XML body and includes it in the COS signature- successful execution writes admin audit action
admin_trigger_storage_action; details includeaction,driver_type,used_draft_values, andmutates_remote_state
Success response example:
{ "code": "success", "msg": "", "data": { "action": "configure_tencent_cos_cors", "tencent_cos_cors": { "rule_id": "asterdrive-presigned-access", "allowed_origins": [ "https://drive.example.com", "https://panel.example.com" ], "request_id": "NmEy...", "preserved_rule_count": 1, "replaced_existing_rule": true, "response_vary": true } }}Common error codes:
| Code | Meaning |
|---|---|
policy.action_unsupported | The action does not support this policy or driver type |
policy.action_parameter_required | Required backend configuration is missing, such as an empty public_site_url |
policy.action_parameter_invalid | Action parameters or backend-derived parameters are invalid |
storage.auth_failed | COS credentials are wrong or signing failed |
storage.permission_denied / storage.permission | COS CAM permissions are insufficient, for example missing name/cos:PutBucketCORS |
storage.misconfigured | COS reports a configuration error, such as bad bucket, endpoint, required headers, or XML |
storage.transient_failure / storage.transient | COS or network failure that may be retried later |
Storage migrations
Section titled “Storage migrations”Admins can create and resume cross-policy blob migration tasks.
| Method | Path | Description |
|---|---|---|
POST | /admin/storage-migrations | Create storage-policy migration task |
POST | /admin/storage-migrations/dry-run | Preflight migration plan without creating a task |
POST | /admin/storage-migrations/{task_id}/resume | Resume existing migration task |
POST | /admin/policies/{id}/recovery-probe | Read-only sample probe for recoverable source content |
POST | /admin/policies/{id}/forced-purge-preview | Build current permanent-purge impact, blockers, and confirmation phrase |
POST | /admin/policies/{id}/forced-purge | Create a digest- and phrase-confirmed permanent-purge task |
Create request:
{ "source_policy_id": 1, "target_policy_id": 2, "mode": "normal"}Rules:
- source and target policy IDs must be positive and different
- storage migration has no source-deletion option; deleting the source policy remains an explicit administrator action after migration
recover_availablerequires the latest recovery probe hash; execution revalidates source and target policy revisions- recovery probes perform metadata plus bounded range reads without writing or deleting source objects
- recovery tasks migrate virtual-empty content first, then preserve every readable stored blob while leaving missing rows protected on the source policy; the source policy itself is never deleted by the task
dry-runchecks target stream-upload support and performs a write/delete probe- capacity checks use the bytes still expected to be copied, not the whole source policy size
insufficientcapacity blocks task creation;unsupportedandunavailablebecome warnings- opaque key conflicts are counted and resolved by writing migrated blobs under new
migration-...keys - task kind is
BackgroundTaskKind::StoragePolicyMigration - migration tasks have independent checkpoints and resume support
- content SHA-256 blobs can be merged across policies only when hash is 64-hex and size also matches
- opaque blobs are never merged across policies
- forced purge is blocked only by placement targets; active upload sessions are reported and abandoned locally by the confirmed task, while completed sessions are not counted as active
- forced purge removes complete file histories referencing source-policy blobs, including direct shares, trash entries, and quota, before deleting unreferenced blob metadata and the policy
Remote nodes
Section titled “Remote nodes”Remote nodes are follower storage nodes managed by the primary, mainly for driver_type = "remote" policies.
| Method | Path | Description |
|---|---|---|
GET | /admin/remote-nodes | Paginated managed follower nodes |
POST | /admin/remote-nodes | Create remote-node record |
GET | /admin/remote-nodes/{id} | Read remote-node details |
PATCH | /admin/remote-nodes/{id} | Update name, base URL, transport mode, or enabled state |
DELETE | /admin/remote-nodes/{id} | Delete remote node; rejected while referenced by policies |
POST | /admin/remote-nodes/{id}/test | Test saved remote-node connection |
POST | /admin/remote-nodes/test | Test draft remote-node connection |
POST | /admin/remote-nodes/{id}/enrollment-token | Generate follower enrollment command |
GET | /admin/remote-nodes/{id}/storage-target-connectors | List follower-owned remote storage target connector descriptors and localization catalog; accepts locale |
GET | /admin/remote-nodes/{id}/storage-targets | List follower remote storage targets |
POST | /admin/remote-nodes/{id}/storage-targets | Create follower remote storage target |
PATCH | /admin/remote-nodes/{id}/storage-targets/{target_key} | Update follower target; referenced targets reject connector-config changes but allow display-name and credential-only updates |
DELETE | /admin/remote-nodes/{id}/storage-targets/{target_key} | Delete an unreferenced follower target; rejected while any storage policy binds the same node and target key |
The remote target API uses the same connector descriptors and connection envelope as storage policies. The legacy /ingress-profile-drivers, /ingress-profiles, and /storage-target-drivers paths are removed; clients must use /storage-target-connectors and /storage-targets. DTO field names use target_key.
A remote policy’s remote_node_id, remote_storage_target_key, and base_path form one immutable physical location after explicit binding. To move data, create another policy and use the policy-to-policy storage migration workflow; transport strategies and other non-location settings remain editable. As a narrow 0.5.1 upgrade exception, a legacy policy whose target key is empty may select one applied target while keeping its node and base path unchanged; it becomes immutable afterwards. The primary serializes policy creation/deletion and target mutation with the storage-topology lock so a concurrent policy cannot appear after a target reference check.
Create example:
{ "name": "edge-sh-01", "base_url": "", "transport_mode": "auto", "is_enabled": true}Notes:
transport_modesupportsdirect,reverse_tunnel, andautodirectrequires a primary-reachablebase_urlreverse_tunnelrequires the follower to actively connect back to/api/v1/internal/remote-tunnel/*autouses direct whenbase_urlis non-empty and reverse tunnel otherwise- empty
base_urlusually means the enrollment flow will complete binding later - remote-node details include
transport_mode,enrollment_status,last_probe_error,capabilities,last_probe_at, andtunnel last_probe_errorandlast_probe_atbelong to the explicit capability probe or connection test; they describe the most recent probe rather than reverse-tunnel runtime healthtunnel.statusis derived from recent poll / stream handshakes and the online TTL;tunnel.last_handshake_atis the primary’s most recent successful handshake timetunnel.runtime_erroris transient reverse-tunnel runtime telemetry. The next successful poll / stream handshake clears it; it is not a historical error log and must not be conflated with the node probelast_probe_error- The renamed fields are the public management contract: the old names are removed without response aliases, so API clients must migrate to
last_probe_error,last_probe_at,tunnel.runtime_error, andtunnel.last_handshake_attogether. The database migration renames columns in place and preserves their values. - reverse tunnel cannot be combined with remote browser presigned upload / download strategies
- remote storage target request bodies match the follower internal storage protocol; see Internal storage protocol
External authentication providers
Section titled “External authentication providers”External auth providers are configured by admins. Anonymous login reads only enabled public summaries. Supported provider kinds are oidc, generic_oauth2, github, qq, google, and microsoft.
| Method | Path | Description |
|---|---|---|
GET | /admin/external-auth/provider-kinds | List supported provider kinds |
GET | /admin/external-auth/providers | Paginated providers |
POST | /admin/external-auth/providers | Create provider |
POST | /admin/external-auth/providers/test | Test draft provider config |
GET | /admin/external-auth/providers/{id} | Read provider details |
PATCH | /admin/external-auth/providers/{id} | Update provider |
DELETE | /admin/external-auth/providers/{id} | Delete provider |
POST | /admin/external-auth/providers/{id}/test | Test saved provider |
OIDC example:
{ "provider_kind": "oidc", "display_name": "Corp SSO", "icon_url": "/static/external-auth/corp.svg", "issuer_url": "https://idp.example.com", "client_id": "asterdrive", "client_secret": "secret", "scopes": "openid email profile", "enabled": true, "auto_provision_enabled": true, "auto_link_verified_email_enabled": true, "require_email_verified": true, "allowed_domains": ["example.com"]}Generic OAuth2 example:
{ "provider_kind": "generic_oauth2", "display_name": "Logto", "icon_url": "/static/external-auth/oauth-logo.svg", "issuer_url": "https://id.example.com", "authorization_url": "https://id.example.com/oidc/auth", "token_url": "https://id.example.com/oidc/token", "userinfo_url": "https://id.example.com/oidc/me", "client_id": "asterdrive", "client_secret": "secret", "scopes": "openid email profile", "enabled": true, "auto_provision_enabled": false, "auto_link_verified_email_enabled": false, "require_email_verified": true}Microsoft example:
{ "provider_kind": "microsoft", "display_name": "Microsoft", "icon_url": "/static/external-auth/microsoft-logo.svg", "options": { "microsoft": { "tenant": "organizations" } }, "client_id": "00000000-0000-0000-0000-000000000000", "client_secret": "secret-value", "scopes": "openid profile email", "enabled": true, "auto_provision_enabled": false, "auto_link_verified_email_enabled": false, "require_email_verified": false}Implementation notes:
- provider
keyis generated by the server and used in/auth/external-auth/{kind}/{provider}/start - URLs must be HTTPS except localhost; fragments are not allowed
oidcsupports discovery;generic_oauth2uses manual authorization / token / userinfo endpointsgithub,qq,google, andmicrosoftare dedicated provider kinds; endpoints and default claim semantics are fixed by backend drivers, so unsupported manual endpoint fields should not be sentmicrosofttenant configuration usesoptions.microsoft.tenant, which acceptscommon,organizations,consumers, or a concrete tenant UUID; provider details return normalizedoptionsoptionsis currently used for provider-specific configuration;options.microsoftis rejected for non-Microsoft providers- provider capabilities and field requirements come from
GET /admin/external-auth/provider-kinds client_secretis redacted as***REDACTED***when reading details, andclient_secret_configuredreports whether a saved secret exists- auto-provisioning can create local users, with optional email-domain restrictions
- verified-email auto-linking can bind external identities to existing local users
- when
require_email_verifiedis enabled, unverified external emails go through/auth/external-auth/email-verification/* - dedicated provider behavior is documented in External Authentication Module
- create, update, delete, and test write admin audit logs
File and blob management
Section titled “File and blob management”These endpoints are admin-side observability and maintenance surfaces, not business file APIs.
| Method | Path | Description |
|---|---|---|
GET | /admin/files | Inspect file records, owning blobs, and version summaries |
GET | /admin/files/{id} | Inspect one file and its versions |
GET | /admin/file-blobs | Inspect blob records, hash kinds, and reference counts |
GET | /admin/file-blobs/{id} | Inspect one blob’s file and version references |
POST | /admin/file-blobs/maintenance | Create maintenance task for selected blobs |
PUT | /admin/folders/{id}/policy | Set or clear an explicit folder policy across personal / team scopes |
Filters:
/admin/files:name,blob_id,policy_id,owner_user_id,team_id,deleted,limit,offset,sort_by,sort_order/admin/file-blobs:hash,policy_id,storage_path,ref_count_min,ref_count_max,size_min,size_max,limit,offset,sort_by,sort_order
hash_kind is derived for observability: 64-hex SHA-256 is content_sha256, everything else is opaque.
Maintenance request:
{ "action": "ref_count_reconcile", "blob_ids": [1, 2, 3]}Supported actions:
integrity_check: check object existence and size onlyref_count_reconcile: recompute and fixref_countorphan_cleanup: recompute references, then clean blobs whose actual references andref_countare both zero
The admin folder-policy request is { "policy_id": 12 }; { "policy_id": null } clears the explicit folder policy. A non-null ID must be positive and identify a policy eligible for folder binding. Locked or trashed folders reject the change. Success returns the updated FolderInfo, records a folder_policy_change audit event, and publishes a storage change event.
Policy groups
Section titled “Policy groups”| Method | Path | Description |
|---|---|---|
GET | /admin/policy-groups | List storage policy groups |
POST | /admin/policy-groups | Create policy group |
GET | /admin/policy-groups/{id} | Read policy group details |
PATCH | /admin/policy-groups/{id} | Update policy group |
DELETE | /admin/policy-groups/{id} | Delete policy group |
POST | /admin/policy-groups/{id}/migrate-assignments | Migrate user and team policy group bindings by updating policy_group_id |
Policy groups define storage policy selection for users and teams. A group configuration still requires at least one policy item. A policy group with user or team bindings must be migrated before deletion, including the last default group; once deletion succeeds, deleting the last default group returns the system to needs_storage without clearing bindings. Other referenced groups remain protected. Migration responses report affected_users, affected_teams, and migrated_assignments.
| Method | Path | Description |
|---|---|---|
GET | /admin/users | Paginated users |
POST | /admin/users | Create user |
GET | /admin/users/{id} | Read user details |
PATCH | /admin/users/{id} | Update user profile, role, status, quota, policy group, or forced password-change flag |
PUT | /admin/users/{id}/password | Reset a user’s password |
DELETE | /admin/users/{id}/mfa | Clear a user’s MFA setup and revoke sessions |
POST | /admin/users/{id}/sessions/revoke | Revoke all existing sessions for the user |
DELETE | /admin/users/{id} | Delete user |
GET | /admin/users/{id}/avatar/{size} | Read uploaded user avatar |
POST | /admin/users/invitations | Create user invitation |
GET | /admin/users/invitations | Paginated user invitations |
POST | /admin/users/invitations/{id}/revoke | Revoke a pending invitation |
User lists support keyword / role / status style filtering and offset pagination. Avatar responses are raw binary and are not wrapped JSON.
POST /admin/users accepts an optional password and optional must_change_password. When password is omitted or blank, the server generates a 24-character temporary password, sets must_change_password = true, and returns the generated value once in generated_password. When a password is provided, must_change_password defaults to false unless the request explicitly sets it.
Invitation creation accepts { "email": "new-user@example.com" } and returns 201. Any existing pending invitation for the same email is revoked before the new pending record is created, and invitation mail is queued through the outbox. The create response may include the one-time invitation_url; list responses do not expose that token URL again. Lists use limit / offset, statuses are pending, accepted, expired, and revoked, and only pending invitations can be revoked.
PATCH /admin/users/{id} accepts must_change_password: true | false. Setting it to true requires the user to change their password after the next successful login; setting it to false clears the requirement before the user completes that flow. Any change to this flag increments session_version, deletes existing refresh sessions, invalidates the auth snapshot cache, and records admin_update_user audit details including the new must_change_password value.
While the flag is set, successful password, MFA, passkey, and external-auth login completions return:
{ "code": "success", "msg": "", "data": { "status": "password_change_required", "expires_in": 900 }}The issued access token is scoped to password change only. It can call GET /auth/me, PUT /auth/password, and POST /auth/logout; other authenticated routes return 403 with auth.password_change_required. POST /auth/refresh is also rejected while the flag or password-change token scope is present. PUT /auth/password still requires the current password and clears must_change_password after a successful update. The current password is temporary only when an administrator has reset the user’s password; if an administrator only sets must_change_password, the user’s existing password remains the current password.
| Method | Path | Description |
|---|---|---|
GET | /admin/teams | Paginated teams |
POST | /admin/teams | Create team and assign initial admin |
GET | /admin/teams/{id} | Read team details |
PATCH | /admin/teams/{id} | Update team |
DELETE | /admin/teams/{id} | Archive a team |
POST | /admin/teams/{id}/restore | Restore an archived team |
GET | /admin/teams/{id}/audit-logs | Read team audit logs |
GET | /admin/teams/{id}/audit-logs/export | Stream a CSV export for a team |
GET | /admin/teams/{id}/members | Paginated team members |
POST | /admin/teams/{id}/members | Add team member |
PATCH | /admin/teams/{id}/members/{member_user_id} | Update member role |
DELETE | /admin/teams/{id}/members/{member_user_id} | Remove team member |
Admin team creation can create a team for another user and give that user the initial team-admin role. User-side POST /teams is more restrictive.
Shares, tasks, config, locks, and audit
Section titled “Shares, tasks, config, locks, and audit”| Method | Path | Description |
|---|---|---|
GET | /admin/shares | Paginated share audit / management list |
DELETE | /admin/shares/{id} | Delete share |
GET | /admin/tasks | Paginated all background tasks |
POST | /admin/tasks/cleanup | Delete finished task records matching filters |
GET | /admin/config | List runtime config entries |
GET | /admin/config/schema | Read system config schema |
GET | /admin/config/template-variables | Read template variable catalog |
GET | /admin/config/media-processing-status | Read configured, runtime-available, and effective media processor status |
GET | /admin/config/{key} | Read one runtime config entry |
PUT | /admin/config/{key} | Set runtime config entry |
DELETE | /admin/config/{key} | Delete custom runtime config entry |
POST | /admin/config/{key}/action | Execute a config action for supported keys |
GET | /admin/locks | Paginated lock list |
DELETE | /admin/locks/{id} | Release a lock |
DELETE | /admin/locks/expired | Delete expired locks |
GET | /admin/audit-logs | Paginated audit logs |
GET | /admin/audit-logs/export | Stream a CSV export using filters and sorting |
The export endpoint ignores limit and offset, reads keyset cursor batches, and rejects matches over 100,000 rows with operation.resource_limit_exceeded. CSV output is UTF-8 with RFC 4180 escaping and this fixed column order:
id,created_at,actor_user_id,actor_username,action,entity_type,entity_id,entity_name,detail,ip_address,user_agent,member_user_id,member_username,role,previous_role,next_role
created_at uses UTC RFC3339. detail contains stored JSON after recursive removal of password, token, secret, credential, authorization, cookie, recovery-code, key, and API-key fields. Empty values remain empty.
Runtime config entries defined by the system cannot be deleted; custom entries can. The single source of truth for system config definitions is src/config/definitions.rs.
Authentication controls include auth_password_login_enabled, which defaults to
true. Setting it to false closes public local-password entry points while
leaving administrator password assignment and authenticated password management
available. Disabling both password and Passkey login requires an enabled external
provider; the last enabled external provider is then protected from disable/delete.
Archive and WebDAV operational keys include:
archive_compress_enableddefaults totrueand gates/batch/archive-compress; disabling it returnsarchive_compress.disabled.archive_download_user_enableddefaults totrueand gates creation and consumption of personal/team ZIP download tickets; disabling it returnsarchive_download.user_disabled.archive_download_share_enableddefaults totrueand gates creation and consumption of public-share ZIP download tickets; disabling it returnsarchive_download.share_disabled.webdav_max_active_locks_per_userdefaults to1024; newLOCKrequests are rejected after the user reaches that ceiling.webdav_download_audit_coalesce_window_secsdefaults to30seconds and coalesces repeated WebDAV download audit records for the same account, file, request type, and client fingerprint. Set it to0to record every read.
Media-derivative limits are regular runtime config entries. thumbnail_max_source_bytes bounds which original files are accepted for thumbnail generation, while thumbnail_max_dimension and image_preview_max_dimension bound the rendered longest edge for list thumbnails and preview-panel images. Changing a dimension creates a dimension-specific derivative cache namespace instead of rewriting another configured size.
Custom runtime config entries also have a visibility field:
| Visibility | Behavior |
|---|---|
private | Admin-only; never returned by /api/v1/public/custom-config |
public | Readable without login |
authenticated | Returned only when the request carries a valid access token |
The field only applies to source = "custom" entries. Built-in system configuration cannot be made public through it. When omitted, new custom entries default to private.
GET /admin/config now includes visibility in addition to id, key, value, source, namespace, updated_at, and updated_by. Sensitive values are still redacted as ***REDACTED***.
GET /admin/config/media-processing-status does not modify persisted configuration. It probes the current instance and returns configured_enabled, runtime_available, effective_enabled, and an optional unavailable_reason for each media processor. command_not_found never includes the configured local command path, so administrators can explain a full/slim image mismatch without exposing host details.
The frontend custom-configuration read path is documented in Public API under GET /public/custom-config. That endpoint only returns the key/value map visible to the current request identity and does not expose admin-only fields.
Admin task APIs can see system tasks and blob-level cache tasks that ordinary users normally cannot see.
Link import is controlled by the offline_download_* runtime config keys. offline_download_engine_registry_json is the current structured engine registry: it contains ordered builtin and aria2 engine entries with enabled flags. Enabled engines are tried in registry order; if all engines are disabled, link import is disabled. The older offline_download_engine single-value key remains as a compatibility fallback when the registry is absent or invalid.
offline_download_temp_dir is the staging root for link-import tasks. When blank, AsterDrive uses the default server temp directory. When set, it must be the same absolute path visible to both AsterDrive and any external downloader such as aria2.
File size, per-task speed, concurrency, and request timeout apply to all engines. When the aria2 registry entry is enabled, the aria2 RPC URL, RPC secret, RPC timeout, split, per-server connection count, and low-speed limit keys configure the administrator-managed aria2 JSON-RPC daemon. AsterDrive does not pass through arbitrary aria2 options, and the per-task speed limit maps to aria2 max-download-limit, not a daemon-wide limit. Admins can execute test_aria2_rpc against offline_download_engine_registry_json; the server probes aria2 with aria2.getVersion. Config actions may include unsaved form drafts in value and draft_values, so the aria2 probe can test the current registry, RPC URL, secret, and timeout before saving. Wrong RPC secrets return code = "offline_download.aria2_rpc_auth_failed"; other probe failures return code = "offline_download.aria2_rpc_probe_failed" instead of storage-driver error codes. Operational setup, temporary-directory semantics, and troubleshooting live in Offline Download.
When aria2 is enabled, AsterDrive still validates the HTTP/HTTPS source URL before dispatching the task, but the aria2 daemon performs its own DNS resolution and outbound connection. Operators should isolate the daemon at the network layer and restrict the JSON-RPC endpoint to AsterDrive.
Operational notes
Section titled “Operational notes”- Admin endpoints are intentionally grouped around operational ownership: storage, users, teams, shares, tasks, config, locks, audit, and observability.
- Many admin actions write audit logs.
- For storage behavior involving remote followers, read this page together with Internal storage protocol.
- For user-facing file semantics, read Files, Folders, and Teams instead of treating admin observability endpoints as business APIs.