Skip to content

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.

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.

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.

Any JSON endpoint accepts pretty=true to indent the response (e.g. GET /v1/configure/volumes?pretty=true); the default is compact.

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).

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 /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.

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>"}.

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 /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.

TablePrimary KeyOperationsDescription
accountsidlist, get, updateUser accounts
block-apiscodelist, getBlock store API types
block-storesidallBlock store configurations
meta-storesidallMetadata store registrations
providerscodeallCloud providers
proxy-groupsidallProxy groups
regionsprovider_code, codeallProvider regions (composite key)
volumesidallVolumes
volume-proxy-groupsvolume_id, proxy_group_idlist, get, create, deleteVolume-to-proxy-group associations
volume-statsnonelistUsage statistics reported by metadata servers, newest first
volume-tokenstokenallVolume access tokens
POST /v1/volumes
Authorization: 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).

FieldTypeDefaultDescription
namestringflexfs-<hex>Volume name. Lowercased; 3 to 63 characters.
provider, region, block_apistring""Placement by provider, region, and block API
meta_store, block_storeint640Placement by store ID
proxy_groupint640Proxy group ID to associate; 0 = none, a negative value = a random proxy group in provider and region
block_sizeint644194304Block size in bytes: 256 KiB, 512 KiB, 1 MiB, 2 MiB, 4 MiB, or 8 MiB
compressionbooltrueCompress blocks. With compression_algo empty, uses lz4.
compression_algostring""lz4, snappy, or zstd
encryptionboolfalseEnable end-to-end encryption
flagsstring""Comma-separated volume flags (see Accepted Volume and Token Flags)
max_bytesint640Storage quota in bytes
max_inodesint640Inode quota
notesstring""Free-form notes
retentionint640Retention 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 /v1/volumes/for-token/settings
Authorization: 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 /v1/volumes/{volumeID}/settings
Authorization: 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.

PATCH /v1/volumes/for-token/secret-id
Authorization: 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 /v1/volumes/for-name/{volumeName}/tokens
Authorization: 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.

PATCH /v1/volumes/for-name/{volumeName}/quota
Authorization: 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.

FieldTypeDescription
max_bytesint64Storage quota in bytes, rounded up to a whole block when recorded. 0 leaves the storage quota unchanged.
max_inodesint64Inode 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 /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 /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.

GET /deploy/install-mount.sh

Returns a shell script that downloads and configures the mount client. No authentication required.

GET /deploy/{channel}/{version}/linux/{arch}/mount.flexfs

Serves 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.

GET /deploy/{channel}/{version}/version

Returns, 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.

POST /v1/volumes/stats
Authorization: Bearer <meta-token>
Content-Type: application/json

Accepts 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 /v1/volumes/retired
Authorization: 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 /v1/rate-bins
Authorization: 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.

GET /status

Returns server health status. No authentication required, and no version slug.