AIStor Tables API Reference
AIStor Tables implements native Apache Iceberg tables support directly within MinIO AIStor object storage, eliminating dependencies on external catalog services or metadata databases. The AIStor Tables API is a REST interface that implements a subset of the Iceberg REST Catalog specification and adds endpoints of its own. For the endpoint-by-endpoint breakdown, see Supported endpoints and extensions.
Iceberg clients typically require a base path consisting of the MinIO AIStor endpoint and catalog API path (https://aistor.example.net:9000/_iceberg).
Refer to the documentation for your preferred client, library, or application for specific behaviors around endpoint construction.
All API requests use the following base path:
http://example.net:9000/_iceberg/v1
Replace example.net with your MinIO AIStor server hostname or IP address.
Supported endpoints and extensions
AIStor Tables implements a subset of the Apache Iceberg REST Catalog specification and adds MinIO AIStor extension endpoints of its own.
The catalog classifies every route it registers as one or the other, and it advertises only the specification endpoints in the endpoints field of the catalog configuration response.
The catalog serves both kinds of endpoint the same way, and both require the same authentication.
The following tables record which endpoints the catalog registers and how it classifies each one. They do not state how completely each operation is implemented.
Paths in these tables are relative to the base path /_iceberg/v1.
The catalog is not the only table-related API MinIO AIStor serves: sharing tables with an external consumer uses the Delta Sharing API, which has its own base path and its own documentation.
See Delta Sharing.
Iceberg REST catalog endpoints
The catalog registers these endpoints as part of the Iceberg REST Catalog specification.
Get catalog configuration lists them in its endpoints field, with {prefix} in place of {warehouse}.
| Method | Path | Operation | Description |
|---|---|---|---|
| POST | /{warehouse}/namespaces |
CreateNamespace | Create a namespace in a warehouse. |
| GET | /{warehouse}/namespaces |
ListNamespaces | List the namespaces in a warehouse. |
| GET | /{warehouse}/namespaces/{namespace} |
GetNamespace | Return namespace metadata and properties. |
| HEAD | /{warehouse}/namespaces/{namespace} |
NamespaceExists | Check whether a namespace exists. |
| DELETE | /{warehouse}/namespaces/{namespace} |
DeleteNamespace | Delete an empty namespace. |
| POST | /{warehouse}/namespaces/{namespace}/properties |
UpdateNamespaceProperties | Add, change, or remove namespace properties. |
| POST | /{warehouse}/namespaces/{namespace}/tables |
CreateTable | Create a table with a schema, partitioning, and properties. |
| GET | /{warehouse}/namespaces/{namespace}/tables |
ListTables | List the tables in a namespace. |
| POST | /{warehouse}/namespaces/{namespace}/register |
RegisterTable | Register an existing Iceberg table from its metadata file. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table} |
LoadTable | Return table metadata, including schema and partition information. |
| HEAD | /{warehouse}/namespaces/{namespace}/tables/{table} |
TableExists | Check whether a table exists. |
| POST | /{warehouse}/namespaces/{namespace}/tables/{table} |
CommitTable | Apply table metadata updates atomically. |
| DELETE | /{warehouse}/namespaces/{namespace}/tables/{table} |
DeleteTable | Delete a table, with optional purging of its data. |
| POST | /{warehouse}/tables/rename |
RenameTable | Rename a table, and optionally move it to another namespace. |
| POST | /{warehouse}/transactions/commit |
CommitMultiTableTransaction | Commit changes across several tables atomically. |
| POST | /{warehouse}/namespaces/{namespace}/tables/{table}/metrics |
TableMetrics | Accept a table scan metrics report from a client. |
| POST | /{warehouse}/namespaces/{namespace}/views |
CreateView | Create a view with a schema and a SQL definition. |
| GET | /{warehouse}/namespaces/{namespace}/views |
ListViews | List the views in a namespace. |
| GET | /{warehouse}/namespaces/{namespace}/views/{view} |
LoadView | Return view metadata, including schema and SQL definition. |
| HEAD | /{warehouse}/namespaces/{namespace}/views/{view} |
ViewExists | Check whether a view exists. |
| POST | /{warehouse}/namespaces/{namespace}/views/{view} |
CommitView | Apply view metadata updates atomically. |
| DELETE | /{warehouse}/namespaces/{namespace}/views/{view} |
DropView | Delete a view. |
| POST | /{warehouse}/views/rename |
RenameView | Rename a view, and optionally move it to another namespace. |
| POST | /{warehouse}/namespaces/{namespace}/register-view |
RegisterView | Register an existing Iceberg view. |
| GET | /config |
GetConfig | Return catalog configuration for client discovery. |
MinIO AIStor extension endpoints
The Iceberg REST Catalog specification does not define these endpoints.
The catalog serves them, but leaves them out of the endpoints field of the catalog configuration response.
| Method | Path | Operation | Description |
|---|---|---|---|
| POST | /warehouses |
CreateWarehouse | Create a warehouse and its underlying bucket. |
| GET | /warehouses |
ListWarehouses | List the warehouses in the cluster. |
| GET | /warehouses/{warehouse} |
GetWarehouse | Return warehouse metadata. |
| DELETE | /warehouses/{warehouse} |
DeleteWarehouse | Delete a warehouse that no longer contains namespaces. |
| PUT | /warehouses/{warehouse}/encryption |
PutWarehouseEncryption | Set the default encryption for a warehouse. |
| GET | /warehouses/{warehouse}/encryption |
GetWarehouseEncryption | Return the default encryption for a warehouse. |
| DELETE | /warehouses/{warehouse}/encryption |
DeleteWarehouseEncryption | Remove the default encryption from a warehouse. |
| GET | /warehouses/{warehouse}/tags |
ListWarehouseTags | List the tags on a warehouse. |
| POST | /warehouses/{warehouse}/tags |
TagWarehouse | Add or change tags on a warehouse. |
| DELETE | /warehouses/{warehouse}/tags |
UntagWarehouse | Remove tags from a warehouse. |
| PUT | /{warehouse}/maintenance/{type} |
PutWarehouseMaintenanceConfiguration | Set the warehouse maintenance configuration for one maintenance type. |
| GET | /{warehouse}/maintenance |
GetWarehouseMaintenanceConfiguration | Return all maintenance configurations for a warehouse. |
| PUT | /{warehouse}/namespaces/{namespace}/tables/{table}/maintenance/{type} |
PutTableMaintenanceConfiguration | Override the warehouse maintenance configuration for one table and maintenance type. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/maintenance |
GetTableMaintenanceConfiguration | Return the effective maintenance configuration for a table, which merges any table override with the warehouse default. |
| DELETE | /{warehouse}/namespaces/{namespace}/tables/{table}/maintenance/{type} |
DeleteTableMaintenanceConfiguration | Remove a table override for one maintenance type, so the table inherits the warehouse default again. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/maintenance-job-status |
GetTableMaintenanceJobStatus | Return the last run status for each maintenance type on a table. |
| PUT | /{warehouse}/namespaces/{namespace}/tables/{table}/encryption |
PutTableEncryption | Set table-level encryption, which overrides the warehouse default. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/encryption |
GetTableEncryption | Return the encryption for a table, either its own or the one inherited from the warehouse. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/tags |
ListTableTags | List the tags on a table. |
| POST | /{warehouse}/namespaces/{namespace}/tables/{table}/tags |
TagTable | Add or change tags on a table. |
| DELETE | /{warehouse}/namespaces/{namespace}/tables/{table}/tags |
UntagTable | Remove tags from a table. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/snapshots |
ListTableSnapshots | Return the snapshot history for a table, one page at a time. |
| GET | /{warehouse}/namespaces/{namespace}/tables/{table}/preview |
PreviewTable | Read the first rows of the current snapshot without a query engine. |
| GET | /stats |
GetGlobalStats | Return aggregate statistics for all warehouses. |
Specification endpoints the catalog does not serve
Released versions of the catalog register no route for the following specification endpoints:
| Endpoint group | Paths | Effect on a client |
|---|---|---|
| Scan planning | /plan, /plan/{plan-id}, /tasks |
The client plans scans itself. |
| Table credentials | /credentials |
The client obtains storage credentials another way, such as an access key or a Security Token Service (STS) token. |
Neither group appears in the endpoints field of Get catalog configuration.
Read that field to determine what the catalog you are talking to actually serves, rather than assuming this table matches your version.
Intentional differences from the specification
MinIO AIStor runs the Apache Iceberg REST Compatibility Kit against every release. The following behaviors differ from the specification on purpose, so the matching compatibility tests are excluded:
| Behavior | Difference |
|---|---|
| Slashes in names | A table or namespace name cannot contain a slash. |
| Default column values | Creating a table with a default column value is not supported. |
| Delete table purge default | purgeRequested is a query parameter on the delete request. A delete that sets it to true, or omits it, removes the table metadata and its data files; a delete that sets it to false removes only the registry entry and the pointer, leaving the data intact. MinIO AIStor defaults the parameter to true to work around a Spark client that omits it, and the Iceberg Java client also omits it when purge is false, so a request meant to preserve the data purges it. See apache/iceberg#11023. |
| Register table | Re-registering a table whose data was purged fails, because the data files are gone. |
| Register view | The compatibility suite’s view registration tests are excluded. Deleting a view takes no purge parameter and does not purge table data. |
| Custom view metadata location | Creating a view with a custom metadata location is not supported. |
AWS S3 Tables path aliases
AWS S3 Tables uses the term table bucket for the resource that MinIO AIStor calls a warehouse.
The catalog serves its warehouse encryption, warehouse tags, and warehouse maintenance endpoints under a second, /buckets path.
The table-level endpoints have no /buckets path.
The same handler serves both paths in each of the following pairs.
| Method | Alias path | Extension path |
|---|---|---|
| PUT | /buckets/{warehouse}/encryption |
/warehouses/{warehouse}/encryption |
| GET | /buckets/{warehouse}/encryption |
/warehouses/{warehouse}/encryption |
| DELETE | /buckets/{warehouse}/encryption |
/warehouses/{warehouse}/encryption |
| GET | /buckets/{warehouse}/tags |
/warehouses/{warehouse}/tags |
| POST | /buckets/{warehouse}/tags |
/warehouses/{warehouse}/tags |
| DELETE | /buckets/{warehouse}/tags |
/warehouses/{warehouse}/tags |
| PUT | /buckets/{warehouse}/maintenance/{type} |
/{warehouse}/maintenance/{type} |
| GET | /buckets/{warehouse}/maintenance |
/{warehouse}/maintenance |
Authentication
All requests require AWS Signature Version 4 (SigV4) authentication with the service name s3tables.
Requests must include standard AWS SigV4 headers:
Authorization- AWS SigV4 signatureX-Amz-Date- Request timestampX-Amz-Content-SHA256- Payload hash
Example authentication flow
To authenticate a request:
- Create an HTTP request with method, URL, headers, and body.
- Calculate the payload hash (SHA256 of request body).
- Generate the SigV4 signature using your access key and secret key.
- Add the signature to the
Authorizationheader.
Most AWS SDKs and libraries provide built-in SigV4 signing functionality.
For example, the following Python code uses boto3and botocore:
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import boto3
session = boto3.Session(
aws_access_key_id='your-access-key',
aws_secret_access_key='your-secret-key'
)
request = AWSRequest(
method='POST',
url='http://localhost:9000/_iceberg/v1/warehouses',
data='{"name":"analytics"}',
headers={'Content-Type': 'application/json'}
)
SigV4Auth(session.get_credentials(), 's3tables', 'region').add_auth(request)
Warehouse operations
Warehouses serve as the root container for all tables and namespaces.
Create warehouse
Create a new warehouse for storing tables and namespaces.
POST /_iceberg/v1/warehouses
Request body:
{
"name": "analytics",
"upgrade-existing": false
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Warehouse name (3-63 chars, lowercase/numbers/hyphens). |
upgrade-existing |
boolean | No | Allow upgrading existing bucket to warehouse (default: false). |
Response: 200 OK
{
"name": "analytics"
}
Action: s3tables:CreateWarehouse
Warehouse versioning
MinIO AIStor creates the underlying warehouse bucket with versioning enabled and purge-on-delete configured. Iceberg relies on versioning to recover from failed transactions and to expire snapshots safely, so this configuration is applied automatically at warehouse creation. When you upgrade an existing bucket to a warehouse, the same versioning configuration is applied.
Because warehouse buckets require versioning, you cannot suspend versioning on a warehouse bucket. A PUT bucket-versioning request that attempts to set the Suspended state (or that supplies excluded prefixes) on a warehouse bucket is rejected with HTTP 400 Bad Request and the S3 error code InvalidBucketState (“This bucket is a Tables warehouse, versioning cannot be suspended.”).
List warehouses
Return all warehouses accessible to the authenticated user or service.
GET /_iceberg/v1/warehouses
Query parameters:
| Parameter | Type | Description |
|---|---|---|
pageToken |
string | Pagination token from previous response. |
pageSize |
integer | Maximum number of results to return. |
search |
string | Case-insensitive substring filter applied to warehouse names. |
stats |
boolean | Set to true to return aggregate statistics and switch to index-based pagination. See Listing with search and statistics. |
Response: 200 OK
{
"warehouses": ["analytics", "dev", "staging"],
"next-page-token": "token-for-next-page"
}
Action: s3tables:ListWarehouses
Get warehouse
Retrieve metadata for a specific warehouse.
GET /_iceberg/v1/warehouses/{warehouse}
Response: 200 OK
{
"name": "analytics",
"bucket": "mybucket",
"uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
"created-at": "2025-10-22T10:30:00Z",
"properties": {
"owner": "data-team",
"description": "Data science tables",
"environment": "production"
}
}
Action: s3tables:GetWarehouse
Resource: arn:aws:s3tables:::bucket/{warehouse}
Delete warehouse
Remove a warehouse. The warehouse must be empty (no namespaces) before deletion.
DELETE /_iceberg/v1/warehouses/{warehouse}
Query parameters:
| Parameter | Type | Description |
|---|---|---|
preserve-bucket |
boolean | Keep underlying storage bucket (default: false). |
Response: 204 No Content
Action: s3tables:DeleteWarehouse
Resource: arn:aws:s3tables:::bucket/{warehouse}
Namespace operations
Namespaces organize tables within a warehouse and support custom properties.
Create namespace
Create a new namespace within a warehouse.
POST /_iceberg/v1/{warehouse}/namespaces
Request body:
{
"namespace": ["data_science"],
"properties": {
"owner": "data-team",
"description": "Data science tables",
"environment": "production"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
namespace |
array[string] | Yes | Array with one or more namespace names (max 10). |
properties |
object | No | Key-value properties (each key/value max 2KB). |
Response: 200 OK
{
"namespace": ["data_science"],
"properties": {
"owner": "data-team",
"description": "Data science tables",
"environment": "production"
}
}
Action: s3tables:CreateNamespace
Resource: arn:aws:s3tables:::bucket/{warehouse}
List namespaces
Return all namespaces in a warehouse.
GET /_iceberg/v1/{warehouse}/namespaces
Query parameters:
| Parameter | Type | Description |
|---|---|---|
pageToken |
string | Pagination token from previous response. |
pageSize |
integer | Maximum number of results to return. |
parent |
string | Parent namespace for hierarchical listing. |
search |
string | Case-insensitive substring filter applied to namespace names. |
stats |
boolean | Set to true to return aggregate statistics and switch to index-based pagination. See Listing with search and statistics. |
Response: 200 OK
{
"namespaces": [
["data_science"],
["engineering"],
["marketing"]
],
"next-page-token": "token-for-next-page"
}
Action: s3tables:ListNamespaces
Resource: arn:aws:s3tables:::bucket/{warehouse}
Get namespace
Retrieve namespace properties.
GET /_iceberg/v1/{warehouse}/namespaces/{namespace}
Response: 200 OK
{
"namespace": ["data_science"],
"properties": {
"owner": "data-team",
"description": "Data science tables"
}
}
Action: s3tables:GetNamespace
Resource: arn:aws:s3tables:::bucket/{warehouse}
Update namespace properties
Update or add namespace properties.
POST /_iceberg/v1/{warehouse}/namespaces/{namespace}/properties
Request body:
{
"updates": {
"owner": "new-team",
"description": "Updated description"
},
"removals": ["environment"]
}
Response: 200 OK
{
"updated": ["owner", "description"],
"removed": ["environment"],
"missing": []
}
Action: s3tables:UpdateNamespaceProperties
Delete namespace
Remove a namespace. The namespace must be empty (no tables) before deletion.
DELETE /_iceberg/v1/{warehouse}/namespaces/{namespace}
Response: 204 No Content
Action: s3tables:DeleteNamespace
Resource: arn:aws:s3tables:::bucket/{warehouse}
Table operations
Tables are Apache Iceberg tables with schema, partitioning, and transaction support.
Create table
Create a new table with specified schema and optional partitioning.
POST /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables
Request body:
{
"name": "orders",
"schema": {
"type": "struct",
"fields": [
{
"id": 1,
"name": "order_id",
"type": "long",
"required": true
},
{
"id": 2,
"name": "customer_id",
"type": "long",
"required": true
},
{
"id": 3,
"name": "order_date",
"type": "date",
"required": true
},
{
"id": 4,
"name": "amount",
"type": "decimal(10,2)",
"required": true
}
]
},
"partition-spec": [
{
"name": "order_date_year",
"transform": "year",
"source-id": 3,
"field-id": 1000
}
],
"properties": {
"owner": "orders-team",
"description": "Order transactions"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Table name (1-250 chars, lowercase/numbers/underscores) |
schema |
object | Yes | Iceberg schema with field definitions |
partition-spec |
array | No | Partition specification (default: unpartitioned) |
write-order |
object | No | Sort order for data files |
properties |
object | No | Table properties (max 2KB each) |
stage-create |
boolean | No | Create staged table for atomic commits |
Restrictions:
- MinIO AIStor manages table locations, you cannot specify a custom
location. - Properties cannot begin with
write.data.path. - Most
write.metadata.*properties are not supported.
Response: 200 OK
{
"metadata": {
"format-version": 2,
"table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
"location": "s3://analytics/data_science/orders",
"current-schema-id": 0,
"schemas": [...],
"partition-specs": [...],
"properties": {...}
},
"metadata-location": "s3://analytics/.aistor-tables/data_science/orders/metadata/v1.metadata.json",
"config": {}
}
Action: s3tables:CreateTable
Resource: arn:aws:s3tables:::bucket/{warehouse}/table/*
Conditions:
s3tables:namespace- Restrict by namespace names3tables:tableName- Restrict by table name
Staged table creation
Setting stage-create to true creates the table as a draft. A staged table:
- Is invisible to List tables and cannot be loaded with Get table metadata.
- Returns a
nullmetadata-locationin the create response, which signals that the table is a draft without a final, queryable metadata location.
Finalize a staged table with a subsequent commit to the table endpoint (see Commit table changes). The commit marks the table as live, populates its metadata-location, and makes it visible to List tables. Staging lets you atomically create a table together with its first data commit.
List tables
Return all tables in a namespace.
GET /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables
Query parameters:
| Parameter | Type | Description |
|---|---|---|
pageToken |
string | Pagination token from previous response. |
pageSize |
integer | Maximum number of results to return. |
search |
string | Case-insensitive substring filter applied to table names. |
stats |
boolean | Set to true to return aggregate statistics and switch to index-based pagination. See Listing with search and statistics. |
Response: 200 OK
{
"identifiers": [
{
"namespace": ["data_science"],
"name": "orders"
},
{
"namespace": ["data_science"],
"name": "customers"
}
],
"next-page-token": "token-for-next-page"
}
Action: s3tables:ListTables
Get table metadata
Retrieve complete table metadata including schema, partitioning, and snapshots.
GET /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}
Response: 200 OK
{
"metadata": {
"format-version": 2,
"table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
"location": "s3://analytics/data_science/orders",
"last-updated-ms": 1698854400000,
"current-schema-id": 0,
"schemas": [...],
"current-snapshot-id": 3051729675574597004,
"snapshots": [...],
"partition-specs": [...],
"properties": {...}
},
"metadata-location": "s3://analytics/.aistor-tables/data_science/orders/metadata/v3.metadata.json"
}
Action: s3tables:GetTable
Resource: arn:aws:s3tables:::bucket/{warehouse}/table/*
You can also use a HEAD request to check if a table exists without returning metadata.
HEAD /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}
Response:
200 OK- Table exists404 Not Found- Table does not exist
Commit table changes
Atomically commit changes to a table using optimistic concurrency control.
POST /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}
Request body:
{
"identifier": {
"namespace": ["data_science"],
"name": "orders"
},
"requirements": [
{
"type": "assert-table-uuid",
"uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1"
},
{
"type": "assert-last-assigned-field-id",
"last-assigned-field-id": 4
}
],
"updates": [
{
"action": "append",
"manifest-list": "s3://analytics/data_science/orders/metadata/snap-3051729675574597004.avro"
}
]
}
Commit requirements:
Requirements validate preconditions before applying updates. Common types include:
| Type | Description |
|---|---|
assert-table-uuid |
Verify table UUID matches expected value. |
assert-ref-snapshot-id |
Verify branch/tag points to expected snapshot. |
assert-last-assigned-field-id |
Verify schema field ID counter. |
assert-current-schema-id |
Verify active schema version. |
assert-last-assigned-partition-id |
Verify partition spec ID counter. |
Commit updates:
Updates modify table state atomically. Common actions include:
| Action | Description |
|---|---|
append |
Add new data files via manifest list. |
set-properties |
Update table properties. |
remove-properties |
Delete table properties. |
upgrade-format-version |
Upgrade to newer Iceberg format. |
add-schema |
Register new schema version. |
set-current-schema |
Change active schema. |
add-snapshot |
Add new snapshot to table. |
set-snapshot-ref |
Update branch or tag reference. |
Response: 200 OK
{
"metadata": {...},
"metadata-location": "s3://analytics/.aistor-tables/data_science/orders/metadata/v4.metadata.json"
}
Action: s3tables:UpdateTable
Rename table
Move a table to a different namespace or change its name.
POST /_iceberg/v1/{warehouse}/tables/rename
Request body:
{
"source": {
"namespace": ["data_science"],
"name": "orders"
},
"destination": {
"namespace": ["analytics"],
"name": "order_history"
}
}
Response: 204 No Content
Action: s3tables:RenameTable
Delete table
Remove a table from the catalog.
DELETE /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
purgeRequested |
boolean | true | Delete metadata and data files. |
Response: 204 No Content
Purge Behavior:
purgeRequested=true(default) - Remove both catalog metadata and table data files.purgeRequested=false- Remove only catalog entry, preserving data files.
AIStor Tables defaults purgeRequested to true, which differs from the standard Iceberg default of false. This is a deliberate choice for Spark compatibility.
The Iceberg Java client omits the purgeRequested parameter entirely when requesting a drop without purge (dropTable(identifier, false)). Because the parameter is omitted, the server applies its default of true, so dropping a table through Spark or the Java client deletes the data files even when the client intended to preserve them.
To drop a table without purging data files, explicitly pass purgeRequested=false in the query string:
DELETE /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}?purgeRequested=false
The standard Iceberg Java client cannot send this parameter. Applications that require drop-without-purge should use PyIceberg or make a direct REST API call.
The catalog also advertises s3.delete-enabled=false through the Get catalog configuration endpoint to signal well-behaved clients not to attempt client-side file deletion.
Action: s3tables:DeleteTable
Resource: arn:aws:s3tables:::bucket/{warehouse}/table/*
Preview table data
Return a sample of rows from the current snapshot of a table without a query engine. Rows are read directly from the table’s Parquet data files using an Iceberg scan, so no external engine is required.
GET /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}/preview
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 100 | Maximum number of rows to return. Must be a positive integer and cannot exceed 1000. |
Response: 200 OK
{
"schema": [
{ "name": "order_id", "type": "int64" },
{ "name": "amount", "type": "decimal128(10, 2)" }
],
"rows": [
[1001, "42.50"],
[1002, "17.00"]
],
"row_count": 2
}
| Field | Type | Description |
|---|---|---|
schema |
array[object] | Column definitions, each with a name and a type. |
rows |
array[array] | Row values in the same column order as schema. |
row_count |
integer | Number of rows returned in this response. |
A request for a table that does not exist returns 404 Not Found with error type NoSuchTableException.
Action: s3tables:GetTableData
Resource: arn:aws:s3tables:::bucket/{warehouse}/table/*
Get table maintenance job status
Return the last execution status of each automated maintenance job for a table.
GET /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}/maintenance-job-status
Response: 200 OK
{
"tableARN": "arn:aws:s3tables:::bucket/analytics/table/9c12d441-03fe-4693-9a96-a0705ddf69c1",
"status": {
"icebergSnapshotManagement": {
"status": "Successful",
"lastRunTimestamp": "2026-07-24T10:30:00Z"
},
"icebergCompaction": {
"status": "Failed",
"lastRunTimestamp": "2026-07-24T09:15:00Z",
"failureMessage": "compaction aborted"
},
"icebergUnreferencedFileRemoval": {
"status": "Not_Yet_Run"
}
}
}
The status object contains one entry per maintenance type that is configured on the table: icebergSnapshotManagement, icebergCompaction, and icebergUnreferencedFileRemoval. Each entry has the following fields:
| Field | Type | Description |
|---|---|---|
status |
string | Last execution status - one of Successful, Failed, Disabled, or Not_Yet_Run. |
lastRunTimestamp |
string | RFC 3339 timestamp of the last run. Omitted when the job has not run. |
failureMessage |
string | Error detail for a failed run. Omitted when the last run did not fail. |
A maintenance type reports Disabled when it is turned off in the table or warehouse configuration, or when the corresponding maintenance feature is disabled cluster-wide. A type that is enabled but has never executed reports Not_Yet_Run.
You can retrieve the same information from the command line with mc table maintenance status.
Action: s3tables:GetTableMaintenanceJobStatus
Resource: arn:aws:s3tables:::bucket/{warehouse}/table/*
Listing with search and statistics
The List warehouses, List namespaces, and List tables operations support a case-insensitive substring search filter and an optional statistics mode intended for console and UI use.
Search filter
Add search to any list request to return only the entries whose name contains the given substring, matched case-insensitively. The filter works with both the default token-based pagination and the statistics mode described below.
GET /_iceberg/v1/analytics/namespaces/data_science/tables?search=order
Statistics mode
Add stats=true to a list request to include aggregate statistics for each returned entry and switch from token-based pagination to index-based pagination.
GET /_iceberg/v1/warehouses?stats=true&page=0&page_size=100&sort=size&sort_order=desc
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
stats |
boolean | false | Set to true to enable statistics mode. Required to use the page, page_size, sort, sort_order, and ui_token parameters; when set, the index-based page/page_size parameters replace the default token-based pageToken/pageSize. The search filter works in both modes. |
page |
integer | 0 | Zero-based page index. The item offset is page * page_size. |
page_size |
integer | 100 | Number of items per page. Values above 1000 are capped at 1000. |
sort |
string | name | Statistic field to sort by. See the allowed values below. When omitted, entries are ordered by name. |
sort_order |
string | asc | Sort direction - asc or desc. |
search |
string | - | Case-insensitive substring filter applied to entry names. |
ui_token |
string | - | Routing token returned by a previous response. Pass it back on subsequent page requests. |
The allowed sort values depend on the entity being listed:
| Operation | Allowed sort values |
|---|---|
| List warehouses | namespaces, tables, records, size |
| List namespaces | tables, records, size |
| List tables | records, size |
When sort is omitted, entries are ordered by name.
Response headers:
| Header | Description |
|---|---|
X-Minio-Ui-List-Token |
Routing token for the cached listing. Pass it back as ui_token on subsequent page requests so they reach the node that holds the cache. |
X-Minio-Ui-Total-Count |
Total number of items matching the current search filter, for calculating the total page count. |
In statistics mode, the response body adds a stats object keyed by entry name alongside the normal listing fields:
{
"warehouses": ["analytics", "dev"],
"stats": {
"analytics": {
"namespaces": 3,
"tables": 12,
"records": 4500000,
"size": 892000000
}
}
}
Advanced operations
Multi-table transactions
Commit changes to multiple tables atomically.
POST /_iceberg/v1/{warehouse}/transactions/commit
Request body:
{
"table-changes": [
{
"identifier": {
"namespace": ["data_science"],
"name": "orders"
},
"requirements": [...],
"updates": [...]
},
{
"identifier": {
"namespace": ["data_science"],
"name": "customers"
},
"requirements": [...],
"updates": [...]
}
]
}
Response: 200 OK
The transaction succeeds only if all table commits succeed. If any table commit fails, the entire transaction is rolled back.
Get catalog configuration
Retrieve catalog-level configuration and capabilities.
GET /_iceberg/v1/config?warehouse={warehouse}
The warehouse query parameter is required.
The request fails with 400 BadRequest if you omit it.
Response: 200 OK
{
"defaults": {
"prefix": "analytics"
},
"overrides": {
"client.region": "dummy",
"s3.endpoint": "http://localhost:9000",
"s3.path-style-access": "true",
"s3.delete-enabled": "false"
},
"endpoints": [
"GET /v1/{prefix}/namespaces",
"POST /v1/{prefix}/namespaces",
"GET /v1/config"
]
}
The endpoints field lists every Iceberg REST Catalog specification endpoint the catalog registers, with {prefix} in place of {warehouse}.
The preceding example shows three of them.
MinIO AIStor extension endpoints stay reachable but are left out of this field, so that clients that validate the response against the specification parse it cleanly.
For the full lists, see Supported endpoints and extensions.
The catalog returns s3.delete-enabled=false to signal clients not to attempt client-side deletion of table data files. Deletion is handled server-side by the catalog when a table is dropped with purge. See Delete table for details.
Get global statistics
Return system-wide aggregate statistics across all warehouses. This is a MinIO AIStor extension with no AWS S3 Tables equivalent.
GET /_iceberg/v1/stats
Response: 200 OK
{
"warehouses": 3,
"namespaces": 12,
"tables": 148,
"records": 4500000,
"size": 892000000,
"updated_at": "2026-07-24T10:30:00Z"
}
| Field | Type | Description |
|---|---|---|
warehouses |
integer | Total number of warehouses in the system. |
namespaces |
integer | Total number of namespaces across all warehouses. |
tables |
integer | Total number of tables across all warehouses. |
records |
integer | Total number of records across all tables. |
size |
integer | Total size in bytes across all tables. |
updated_at |
string | RFC 3339 timestamp of when the aggregate statistics were last computed. |
Each of the numeric count and size fields is omitted from the response when its value is zero. The updated_at field is always present; before any statistics have been computed it serializes as 0001-01-01T00:00:00Z.
Action: s3tables:ListWarehouses
Additional information
Error responses
All errors return JSON responses with the following structure:
{
"error": {
"code": 409,
"type": "IcebergTableAlreadyExists",
"message": "The specified table already exists."
}
}
| Field | Type | Description |
|---|---|---|
code |
integer | HTTP status code. |
type |
string | Error type identifier for programmatic handling. |
message |
string | Human-readable error description. |
Common error types:
| HTTP Status | Error Type | Description |
|---|---|---|
| 400 | BadRequest |
Invalid request format or parameters. |
| 404 | NoSuchTableException |
Specified table does not exist. |
| 404 | IcebergNamespaceNotFound |
Specified namespace does not exist. |
| 404 | IcebergWarehouseNotFound |
Specified warehouse does not exist. |
| 409 | IcebergTableAlreadyExists |
Table with this name already exists. |
| 409 | IcebergNamespaceAlreadyExists |
Namespace with this name already exists. |
| 409 | IcebergWarehouseAlreadyExists |
Warehouse with this name already exists. |
| 409 | CommitFailedException |
Table commit failed due to conflict or lock. |
| 409 | IcebergNamespaceNotEmptyError |
Cannot delete namespace containing tables. |
| 409 | IcebergWarehouseNotEmpty |
Cannot delete warehouse containing namespaces. |
| 500 | InternalError |
Internal server error occurred. |
| 501 | IcebergPurgeNotSupported |
Purge operation failed. |
| 503 | TableRecoveryInProgress |
Table is recovering from failed transaction. |
Naming constraints
Entity names must follow these rules:
| Entity | Length | Allowed Characters | Notes |
|---|---|---|---|
| Warehouse | 3-63 chars | Lowercase letters, numbers, hyphens | Cannot contain periods. |
| Namespace | 1-250 chars | Lowercase letters, numbers, underscores | May be multilevel, max 10. |
| Table | 1-250 chars | Lowercase letters, numbers, underscores |
Additional constraints:
- Multi-level namespaces: Maximum 10 nested namespaces.
- Custom table locations: Not allowed (MinIO AIStor manages locations).
- Property size: Each property key and value limited to 2KB.
Rate limits
AIStor Tables does not impose hard rate limits but implements best-effort concurrency control:
- Concurrent commits to the same table use optimistic locking.
- Failed commits due to conflicts should be retried with exponential backoff.
- Maximum transaction timeout is configurable per deployment.
AWS S3 Tables compatibility
AIStor Tables is compatible with the AWS S3 Tables API, so tools and clients built for AWS S3 Tables work with minimal or no changes:
- The catalog serves its warehouse encryption, warehouse tags, and warehouse maintenance endpoints under a
/bucketspath as well as the MinIO AIStor path. AWS S3 Tables usesTableBucketfor the concept that MinIO AIStor calls a warehouse. For the pairs, see AWS S3 Tables path aliases. - Policy actions accept both
s3tables:CreateWarehouseands3tables:CreateTableBucketas equivalents. See Controlling access to AIStor Tables. - The ARN format matches the AWS S3 Tables specification.