MinIO AIStor Tables API Reference

MinIO AIStor Tables implements native Apache Iceberg tables support directly within MinIO AIStor object storage, eliminating dependencies on external catalog services or metadata databases. The MinIO AIStor Tables API provides a RESTful interface compatible with the Iceberg REST Catalog specification.

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.

MinIO AIStor creates a dedicated bucket for each MinIO AIStor Tables warehouse. While you may inspect the contents of this bucket with commands like mc ls, to manage warehouses and tables you must use the MinIO AIStor Tables APIs and commands described in this documentation.

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 signature
  • X-Amz-Date - Request timestamp
  • X-Amz-Content-SHA256 - Payload hash

Example authentication flow

To authenticate a request:

  1. Create an HTTP request with method, URL, headers, and body.
  2. Calculate the payload hash (SHA256 of request body).
  3. Generate the SigV4 signature using your access key and secret key.
  4. Add the signature to the Authorization header.

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)
MinIO AIStor Tables uses MinIO AIStor Identity and Access Management (IAM) to control access to data. For more information, see Controlling access to MinIO AIStor Tables

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

IAM actions: s3tables:CreateWarehouse or s3tables:CreateTableBucket

Errors:

  • 400 BadRequest - Invalid warehouse name format
  • 409 IcebergWarehouseAlreadyExists - Warehouse name already in use

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

Response: 200 OK

{
  "warehouses": ["analytics", "dev", "staging"],
  "next-page-token": "token-for-next-page"
}

IAM actions: 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"
  }
}

IAM actions: s3tables:GetWarehouse

IAM resource: arn:aws:s3tables:::bucket/{warehouse}

Errors:

  • 404 IcebergWarehouseNotFound - Warehouse does not exist

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

IAM actions: s3tables:DeleteWarehouse

IAM resource: arn:aws:s3tables:::bucket/{warehouse}

Errors:

  • 404 IcebergWarehouseNotFound - Warehouse does not exist
  • 409 IcebergWarehouseNotEmpty - Warehouse contains namespaces

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

IAM actions: s3tables:CreateNamespace

IAM resource: arn:aws:s3tables:::bucket/{warehouse}

Errors:

  • 400 BadRequest - Invalid namespace name or properties
  • 404 IcebergWarehouseNotFound - Warehouse does not exist
  • 409 IcebergNamespaceAlreadyExists - Namespace already exists

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 (not supported)

Response: 200 OK

{
  "namespaces": [
    ["data_science"],
    ["engineering"],
    ["marketing"]
  ],
  "next-page-token": "token-for-next-page"
}

IAM actions: s3tables:ListNamespaces

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

IAM actions: s3tables:GetNamespace

IAM resource: arn:aws:s3tables:::bucket/{warehouse}

Errors:

  • 404 IcebergNamespaceNotFound - Namespace does not exist

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": []
}

IAM actions: s3tables:UpdateNamespaceProperties

Errors:

  • 404 IcebergNamespaceNotFound - Namespace does not exist

Delete namespace

Remove a namespace. The namespace must be empty (no tables) before deletion.

DELETE /_iceberg/v1/{warehouse}/namespaces/{namespace}

Response: 204 No Content

IAM actions: s3tables:DeleteNamespace

IAM resource: arn:aws:s3tables:::bucket/{warehouse}

Errors:

  • 404 IcebergNamespaceNotFound - Namespace does not exist
  • 409 IcebergNamespaceNotEmptyError - Namespace contains tables

Table operations

Tables are Apache Iceberg tables with schema, partitioning, and transaction support.

Create table

Create a new Iceberg 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": {}
}

IAM actions: s3tables:CreateTable

IAM resource: arn:aws:s3tables:::bucket/{warehouse}/table/*

IAM conditions:

  • s3tables:namespace - Restrict by namespace name
  • s3tables:tableName - Restrict by table name

Errors:

  • 400 BadRequest - Invalid schema, partition spec, or properties
  • 404 IcebergNamespaceNotFound - Namespace does not exist
  • 409 IcebergTableAlreadyExists - Table already exists

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

Response: 200 OK

{
  "identifiers": [
    {
      "namespace": ["data_science"],
      "name": "orders"
    },
    {
      "namespace": ["data_science"],
      "name": "customers"
    }
  ],
  "next-page-token": "token-for-next-page"
}

IAM actions: 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"
}

IAM actions: s3tables:GetTable

IAM resource: arn:aws:s3tables:::bucket/{warehouse}/table/*

Errors:

  • 404 IcebergTableNotFound - Table does not exist

Check if table exists

Check if a table exists without returning metadata.

HEAD /_iceberg/v1/{warehouse}/namespaces/{namespace}/tables/{table}

Response:

  • 200 OK - Table exists
  • 404 Not Found - Table does not exist

IAM actions: s3tables:GetTable

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:

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:

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

IAM actions: s3tables:UpdateTable

Errors:

  • 404 IcebergTableNotFound - Table does not exist
  • 409 CommitFailedException - Requirement check failed or concurrent modification

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

IAM actions: s3tables:RenameTable

Errors:

  • 404 IcebergTableNotFound - Source table does not exist
  • 409 IcebergTableAlreadyExists - Destination table already exists

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) - Removes both catalog metadata and table data files
  • purgeRequested=false - Removes only catalog entry, preserving data files

IAM actions: s3tables:DeleteTable

IAM resource: arn:aws:s3tables:::bucket/{warehouse}/table/*

Errors:

  • 404 IcebergTableNotFound - Table does not exist
  • 501 IcebergPurgeNotSupported - Purge operation failed

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.

Errors:

  • 409 CommitFailedException - One or more table commits failed

Get catalog configuration

Retrieve catalog-level configuration and capabilities.

GET /_iceberg/v1/{warehouse}/config?warehouse={warehouse}

Response: 200 OK

{
  "defaults": {
    "s3.endpoint": "http://localhost:9000"
  },
  "overrides": {}
}

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 IcebergTableNotFound 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
503 TableRecoveryInProgress Table is recovering from failed transaction

AWS S3 Tables compatibility

MinIO AIStor Tables provides compatibility with the AWS S3 Tables API:

  • /buckets is an alias for /warehouses
  • Policy actions support both s3tables:CreateWarehouse and s3tables:CreateTableBucket
  • ARN format matches AWS S3 Tables specification
  • Error response structure follows AWS conventions

This compatibility allows tools and clients built for AWS S3 Tables to work with minimal or no modifications.

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

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

Example

The following example illustrates the basic sequence of operations required to create a warehouse and add data to a table:

  1. Create a warehouse
POST /_iceberg/v1/warehouses
Content-Type: application/json

{"name": "analytics"}
  1. Create a namespace
POST /_iceberg/v1/analytics/namespaces
Content-Type: application/json

{
  "namespace": ["data_science"],
  "properties": {"owner": "data-team"}
}
  1. Create a table
POST /_iceberg/v1/analytics/namespaces/data_science/tables
Content-Type: application/json

{
  "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": "amount", "type": "decimal(10,2)", "required": true}
    ]
  }
}
  1. Load table metadata
GET /_iceberg/v1/analytics/namespaces/data_science/tables/orders
  1. Commit data
POST /_iceberg/v1/analytics/namespaces/data_science/tables/orders
Content-Type: application/json

{
  "identifier": {"namespace": ["data_science"], "name": "orders"},
  "requirements": [
    {"type": "assert-table-uuid", "uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1"}
  ],
  "updates": [
    {
      "action": "append",
      "manifest-list": "s3://analytics/data_science/orders/metadata/snap-123.avro"
    }
  ]
}