Admin REST API
The admin server exposes a REST API over HTTPS (port 443 by default). Every endpoint except the /deploy/ tree and /status requires a Bearer token in the Authorization header, including those that only read.
Versioning
Section titled “Versioning”Every endpoint below is served at both its versioned path (/v1/volumes) and its bare path (/volumes); a bare path always resolves to v1. Pin the versioned path in scripts and new integrations. The /deploy/ tree and the /status health check are exempt and are only ever served unversioned.
Authentication
Section titled “Authentication”All /v1/configure/ endpoints require an account token, as do POST /v1/volumes and the /v1/volumes/for-name/ endpoints. Volume-scoped endpoints (/v1/volumes/for-token/) accept a volume token. Meta-server endpoints (/v1/volumes/stats, /v1/volumes/retired, /v1/rate-bins, and /v1/volumes/{volumeID}/settings) accept a meta store token. DELETE /v1/volumes/{volumeID} accepts either an account token or a meta store token.
Authorization: Bearer <token>Tokens decide who a caller is. Where an access file is in use, a whitelist also decides where it may call from, and a request from an address no rule admits is answered 403 before the token is looked at. Rules name an endpoint by its path template with the /v1 slug removed — /volumes/stats for /v1/volumes/stats. See API Access Control.
Pretty-printing
Section titled “Pretty-printing”Any JSON endpoint accepts pretty=true to indent the response (e.g. GET /v1/configure/volumes?pretty=true); the default is compact.
Configuration CRUD Endpoints
Section titled “Configuration CRUD Endpoints”These endpoints provide generic CRUD operations on all admin resource tables. The {table} parameter corresponds to the API name of the resource (e.g., accounts, volumes, block-stores).
List Resources
Section titled “List Resources”GET /v1/configure/{table}?key=value&...Returns a JSON array of all records in the table. Query parameters are used as filters. Volumes that have been retired and cleaned are left out of volumes; the query parameter cleaned=true returns only those.
Response: 200 OK with JSON array.
Get Resource
Section titled “Get Resource”GET /v1/configure/{table}/{id}GET /v1/configure/{table}/{id1}/{id2}Returns a single record by primary key. Composite-key resources (e.g., regions) use the two-ID form.
Response: 200 OK with JSON object.
Create Resource
Section titled “Create Resource”POST /v1/configure/{table}Content-Type: application/json
{ "field": "value", ... }Creates a new record. A record that duplicates an existing key or unique name is answered 409, and a missing required field, an invalid value, or a reference to a record that does not exist is answered 400.
Response: 200 OK with a JSON object holding the new record’s primary key, e.g. {"id": 5} or {"token": "<uuid>"}.
Update Resource
Section titled “Update Resource”PUT /v1/configure/{table}/{id}PUT /v1/configure/{table}/{id1}/{id2}Content-Type: application/json
{ "field": "new_value", ... }Updates an existing record. Only provided fields are modified. Updating a retired volume is answered 409. Changing a block store’s prefix or bucket name is answered 409 while any volume that has not finished cleanup uses it, and changing an oci block store’s namespace is answered 409 while any such volume has blocks stored.
Response: 204 No Content.
Delete Resource
Section titled “Delete Resource”DELETE /v1/configure/{table}/{id}DELETE /v1/configure/{table}/{id1}/{id2}Deletes a record. For an active volume, this retires the volume rather than removing the row, and deletes its volume tokens. For a retired volume, it removes the row once the volume’s data has been deleted, and is answered 409 (volume data is still being deleted) before then.
A provider, region, block store, meta store, or proxy group that a volume uses is not deleted and is answered 409 (in use by a volume), unless every such volume is retired and its data has been deleted. Deleting a block store, meta store, region, or provider then also deletes the records of those volumes, but not the other stores they used: deleting a block store, for example, leaves their meta store. Deleting a proxy group only detaches those volumes from it. Deleting a provider also deletes its regions, and deleting a region also deletes its block stores, meta stores, and proxy groups. To delete a proxy group that active volumes use, first remove its volume associations.
Response: 204 No Content.
Available Tables
Section titled “Available Tables”| Table | Primary Key | Operations | Description |
|---|---|---|---|
accounts | id | list, get, update | User accounts |
block-apis | code | list, get | Block store API types |
block-stores | id | all | Block store configurations |
meta-stores | id | all | Metadata store registrations |
providers | code | all | Cloud providers |
proxy-groups | id | all | Proxy groups |
regions | provider_code, code | all | Provider regions (composite key) |
volumes | id | all | Volumes |
volume-proxy-groups | volume_id, proxy_group_id | list, get, create, delete | Volume-to-proxy-group associations |
volume-stats | none | list | Usage statistics reported by metadata servers, newest first |
volume-tokens | token | all | Volume access tokens |
Volume Endpoints
Section titled “Volume Endpoints”Create Volume
Section titled “Create Volume”POST /v1/volumesAuthorization: Bearer <account-token>Content-Type: application/json
{ "name": "<volume-name>", "provider": "aws", "region": "<region>", "block_api": "s3", "block_size": 4194304, "max_bytes": 3221225472}Creates a volume. Used by the CSI driver for dynamic provisioning. Responds 200 with the volume identity (the same object as Update Volume Quota).
| Field | Type | Default | Description |
|---|---|---|---|
name | string | flexfs-<hex> | Volume name. Lowercased; 3 to 63 characters. |
provider, region, block_api | string | "" | Placement by provider, region, and block API |
meta_store, block_store | int64 | 0 | Placement by store ID |
proxy_group | int64 | 0 | Proxy group ID to associate; 0 = none, a negative value = a random proxy group in provider and region |
block_size | int64 | 4194304 | Block size in bytes: 256 KiB, 512 KiB, 1 MiB, 2 MiB, 4 MiB, or 8 MiB |
compression | bool | true | Compress blocks. With compression_algo empty, uses lz4. |
compression_algo | string | "" | lz4, snappy, or zstd |
encryption | bool | false | Enable end-to-end encryption |
flags | string | "" | Comma-separated volume flags (see Accepted Volume and Token Flags) |
max_bytes | int64 | 0 | Storage quota in bytes |
max_inodes | int64 | 0 | Inode quota |
notes | string | "" | Free-form notes |
retention | int64 | 0 | Retention in seconds; 0 keeps no history, -1 keeps it forever |
The volume must be placed either by giving both meta_store and block_store IDs, or by naming a provider, region and block API. In the second case the server picks a meta store and a block store in that provider and region at random, preferring a block store whose bucket name starts with flexfs; a meta_store or block_store ID given alongside replaces that pick. A request supplying neither is answered 400. block_api defaults to s3 when the provider is aws; for every other provider it must be given.
max_bytes and max_inodes set the initial quotas, 0 meaning unlimited. The byte figure is converted using the volume’s block size, so the quota in force is the rounded-up block count reported back in the response.
Creating a volume also creates one volume token for it, with the notes auto-created with volume. A repeated request for a name that already has a live volume returns that volume rather than creating a second one, which is what makes a retried provisioning call safe. A name that belongs to a retired volume is answered 409; the name of a retired volume cannot be reused until its record is deleted.
Get Volume Settings (by token)
Section titled “Get Volume Settings (by token)”GET /v1/volumes/for-token/settingsAuthorization: Bearer <volume-token>Returns the volume settings for the token’s associated volume, including block size, compression, encryption, retention, mount flags, and proxy group addresses.
Get Volume Settings (by ID)
Section titled “Get Volume Settings (by ID)”GET /v1/volumes/{volumeID}/settingsAuthorization: Bearer <meta-token>Returns the same volume settings as the by-token form above, addressed by volume ID instead of by volume token. This form requires the meta store token of the metadata server that owns the volume; it is used by metadata servers, which hold volume IDs rather than volume tokens. A token that is not the volume’s assigned meta store token is answered 401, and an unknown volume ID 404.
Update Secret ID (by token)
Section titled “Update Secret ID (by token)”PATCH /v1/volumes/for-token/secret-idAuthorization: Bearer <volume-token>Content-Type: application/json
{ "secret_id": "xxxxxxxx" }Registers the encryption secret ID for the volume. It can be set only once: repeating the stored value succeeds, and a different value is refused.
Response: 204 No Content. A malformed body or secret ID, or a volume without encryption, is answered 400, an unknown volume token 401, and a different secret ID when one is already set 409.
Get Volume Tokens (by name)
Section titled “Get Volume Tokens (by name)”GET /v1/volumes/for-name/{volumeName}/tokensAuthorization: Bearer <account-token>Returns a JSON array holding one volume token for the named volume: the token the CSI driver uses, which is created if the volume does not have one. Returns 404 for an unknown or retired volume name.
Update Volume Quota (by name)
Section titled “Update Volume Quota (by name)”PATCH /v1/volumes/for-name/{volumeName}/quotaAuthorization: Bearer <account-token>Content-Type: application/json
{ "max_bytes": 3221225472, "max_inodes": 0}Ensures a volume’s quotas are at least the given figures. Backs CSI volume expansion.
| Field | Type | Description |
|---|---|---|
max_bytes | int64 | Storage quota in bytes, rounded up to a whole block when recorded. 0 leaves the storage quota unchanged. |
max_inodes | int64 | Inode quota. 0 leaves the inode quota unchanged. |
Quotas only grow through this endpoint: it ensures a volume allows at least the figures given. A value the volume already satisfies leaves the quota unchanged and responds 200 with the figure in force, so a caller that is behind on the volume’s real size does not fail. To reduce a quota, set it directly with configure.flexfs update volume --maxBlocks/--maxInodes.
A volume with no quota in a dimension is refused with 400 for that dimension: there is no limit to raise, and the unlimited sentinel is not a figure a caller can meaningfully record as a capacity.
Responds 200 with the volume identity and the quota now in force:
{ "id": "992467d9-1f45-439d-86e1-2bbb253711c6", "name": "pvc-76021e89-28ed-44d6-82be-34bc4e23a5bb", "max_blocks": 768, "max_bytes": 3221225472, "max_inodes": 0}Returns 404 for an unknown or retired volume name, and 401 for a token that is not an account token.
Delete Volume (by name)
Section titled “Delete Volume (by name)”DELETE /v1/volumes/for-name/{volumeName}Authorization: Bearer <account-token>Retires a volume by name, and deletes its volume tokens. Returns 404 for an unknown volume name.
Response: 204 No Content.
Delete Volume (by ID)
Section titled “Delete Volume (by ID)”DELETE /v1/volumes/{volumeID}Authorization: Bearer <account-token|meta-token>With an account token, retires the volume and deletes its volume tokens. With the meta store token of the volume’s metadata server, marks a retired volume as cleaned; a volume that is not yet retired is answered 400. Repeating either request is not an error.
Response: 204 No Content. An unknown volume ID is answered 204 when the token is a known account or meta store token, and 401 otherwise. For an existing volume, a token that is neither its account token nor its metadata server’s meta store token is answered 401.
Deploy Endpoints
Section titled “Deploy Endpoints”Install Script
Section titled “Install Script”GET /deploy/install-mount.shReturns a shell script that downloads and configures the mount client. No authentication required.
Binary Files
Section titled “Binary Files”GET /deploy/{channel}/{version}/linux/{arch}/mount.flexfsServes the mount client binary. Channels are staging and production, {version} is a release line such as v1.9.x, and {arch} is amd64 (also served as x86_64) or aarch64 (also served as arm64). No authentication required.
Version File
Section titled “Version File”GET /deploy/{channel}/{version}/versionReturns, as plain text, the exact release deployed on that release line of the channel (for example v1.9.3). Mount clients read it to decide whether to update. No authentication required.
Meta-Server Endpoints
Section titled “Meta-Server Endpoints”Post Volume Stats
Section titled “Post Volume Stats”POST /v1/volumes/statsAuthorization: Bearer <meta-token>Content-Type: application/jsonAccepts volume statistics from metadata servers for billing and metering. Statistics for volumes that do not belong to the calling metadata server are ignored.
Response: 204 No Content, or 401 for a token that is not a known meta store token.
Get Retired Volumes
Section titled “Get Retired Volumes”GET /v1/volumes/retiredAuthorization: Bearer <meta-token>Returns the IDs of volumes that have been retired but not yet cleaned, for the authenticated metadata server. There is no time window — a volume appears here until its cleanup completes.
Response: 200 OK with a JSON array of volume-ID strings.
Get Rate Bins
Section titled “Get Rate Bins”GET /v1/rate-binsAuthorization: Bearer <meta-token>Proxies rate bin data from the stat server. Returns a JSON object mapping size bin numbers (0-127) to per-GiB monthly dollar rates ($/GiB/month). An admin server with no stat server credentials reports a single zero rate, so cost is reported as zero instead of failing. Used by metadata servers to compute the cost field in analyze.flexfs and find.flexfs. See Cost and Rate Bin in the glossary.
Status
Section titled “Status”GET /statusReturns server health status. No authentication required, and no version slug.