Skip to main content

Table API

Table endpoints provide operations for creating, reading, updating, and deleting Iceberg tables through the REST Catalog API.

List Tables

List all tables in a namespace.
GET /v1/{prefix}/namespaces/{namespace}/tables

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier (multi-part namespaces use %1F separator)

Query Parameters

pageToken
string
Pagination token from a previous response
pageSize
integer
Maximum number of tables to return

Response

identifiers
array
required
List of table identifiers
next-page-token
string
Token for next page of results

Example

curl -X GET "https://catalog.example.com/v1/production/namespaces/accounting/tables" \
  -H "Authorization: Bearer <token>"
{
  "identifiers": [
    {
      "namespace": ["accounting"],
      "name": "invoices"
    },
    {
      "namespace": ["accounting"],
      "name": "payments"
    }
  ]
}

Create Table

Create a new table in the specified namespace.
POST /v1/{prefix}/namespaces/{namespace}/tables

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier

Headers

Idempotency-Key
string (uuid)
UUIDv7 for idempotent request handling
X-Iceberg-Access-Delegation
string
Comma-separated list of access delegation mechanisms: vended-credentials, remote-signing

Request Body

name
string
required
Table name
location
string
Table location. If not provided, a location will be generated.
schema
object
required
Table schema definition
partition-spec
object
Partition specification
write-order
object
Sort order for data
properties
object
Table properties
stage-create
boolean
If true, table is not created but metadata is initialized for a transaction. Default: false.

Response

metadata-location
string
required
Location of table metadata file
metadata
object
required
Complete table metadata
config
object
Additional configuration for the table

Example

curl -X POST "https://catalog.example.com/v1/production/namespaces/accounting/tables" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F" \
  -d '{
    "name": "invoices",
    "schema": {
      "type": "struct",
      "fields": [
        {"id": 1, "name": "id", "type": "long", "required": true},
        {"id": 2, "name": "amount", "type": "decimal(10,2)", "required": true},
        {"id": 3, "name": "date", "type": "date", "required": true}
      ]
    },
    "partition-spec": {
      "spec-id": 0,
      "fields": [
        {"field-id": 1000, "source-id": 3, "name": "date", "transform": "day"}
      ]
    },
    "properties": {
      "write.format.default": "parquet"
    }
  }'

Load Table

Load table metadata from the catalog.
GET /v1/{prefix}/namespaces/{namespace}/tables/{table}

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier
table
string
required
Table name

Headers

If-None-Match
string
ETag from previous response. Server returns 304 if metadata hasn’t changed.
X-Iceberg-Access-Delegation
string
Access delegation mechanisms

Query Parameters

snapshots
string
Which snapshots to include: all (default) or refs (only referenced snapshots)
referenced-by
string
Comma-separated list of view identifiers referencing this table

Response

metadata-location
string
required
Location of table metadata file
metadata
object
required
Complete table metadata including schema, partition specs, snapshots, etc.
config
object
Additional configuration and credentials for accessing the table

Example

curl -X GET "https://catalog.example.com/v1/production/namespaces/accounting/tables/invoices" \
  -H "Authorization: Bearer <token>" \
  -H "X-Iceberg-Access-Delegation: vended-credentials"
{
  "metadata-location": "s3://bucket/warehouse/accounting/invoices/metadata/v1.metadata.json",
  "metadata": {
    "format-version": 2,
    "table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",
    "location": "s3://bucket/warehouse/accounting/invoices",
    "schemas": [...],
    "current-schema-id": 0,
    "partition-specs": [...],
    "default-spec-id": 0,
    "snapshots": [...],
    "properties": {...}
  },
  "config": {
    "token": "eyJhbGc..."
  }
}

Update Table

Commit updates to table metadata.
POST /v1/{prefix}/namespaces/{namespace}/tables/{table}

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier
table
string
required
Table name

Headers

Idempotency-Key
string (uuid)
UUIDv7 for idempotent request handling

Request Body

requirements
array
required
Assertions that must be true before applying updates
updates
array
required
Changes to apply to table metadata

Response

metadata-location
string
required
Location of new metadata file
metadata
object
required
Updated table metadata

Example

curl -X POST "https://catalog.example.com/v1/production/namespaces/accounting/tables/invoices" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "requirements": [
      {
        "type": "assert-ref-snapshot-id",
        "ref": "main",
        "snapshot-id": 12345
      }
    ],
    "updates": [
      {
        "action": "append",
        "data-files": [...]
      },
      {
        "action": "set-snapshot-ref",
        "ref-name": "main",
        "snapshot-id": 12346
      }
    ]
  }'
The server validates requirements before applying updates. If any requirement fails, the entire commit is rejected with 409 Conflict.

Check Table Exists

Check if a table exists without loading its metadata.
HEAD /v1/{prefix}/namespaces/{namespace}/tables/{table}

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier
table
string
required
Table name

Response

No response body. Status code indicates existence.

Example

curl -I "https://catalog.example.com/v1/production/namespaces/accounting/tables/invoices" \
  -H "Authorization: Bearer <token>"

Drop Table

Delete a table from the catalog.
DELETE /v1/{prefix}/namespaces/{namespace}/tables/{table}

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier
table
string
required
Table name

Query Parameters

purgeRequested
boolean
If true, delete table data and metadata. Default: false.

Headers

Idempotency-Key
string (uuid)
UUIDv7 for idempotent request handling

Response

No response body on success.

Example

curl -X DELETE "https://catalog.example.com/v1/production/namespaces/accounting/tables/invoices?purgeRequested=true" \
  -H "Authorization: Bearer <token>"
With purgeRequested=true, all table data and metadata are permanently deleted and cannot be recovered.

Rename Table

Rename a table or move it to a different namespace.
POST /v1/{prefix}/tables/rename

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments

Headers

Idempotency-Key
string (uuid)
UUIDv7 for idempotent request handling

Request Body

source
object
required
Current table identifier
destination
object
required
New table identifier

Response

No response body on success.

Example

curl -X POST "https://catalog.example.com/v1/production/tables/rename" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "source": {
      "namespace": ["accounting"],
      "name": "invoices"
    },
    "destination": {
      "namespace": ["accounting", "archive"],
      "name": "invoices_old"
    }
  }'
Moving tables across namespaces is valid but not all servers support it. Check the 406 response if cross-namespace moves fail.

Register Table

Register an existing table using its metadata file location.
POST /v1/{prefix}/namespaces/{namespace}/register

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier

Headers

Idempotency-Key
string (uuid)
UUIDv7 for idempotent request handling
X-Iceberg-Access-Delegation
string
Access delegation mechanisms

Request Body

name
string
required
Table name to register
metadata-location
string
required
Location of existing metadata file

Response

Same as Load Table response.

Example

curl -X POST "https://catalog.example.com/v1/production/namespaces/accounting/register" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "imported_invoices",
    "metadata-location": "s3://external-bucket/tables/invoices/metadata/v5.metadata.json"
  }'

Report Metrics

Send table operation metrics to the catalog.
POST /v1/{prefix}/namespaces/{namespace}/tables/{table}/metrics

Path Parameters

prefix
string
required
Optional prefix for multi-tenant deployments
namespace
string
required
Namespace identifier
table
string
required
Table name

Request Body

Metrics report containing scan metrics, commit metrics, etc.

Response

No response body on success.

Example

curl -X POST "https://catalog.example.com/v1/production/namespaces/accounting/tables/invoices/metrics" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "snapshot-id": 12345,
    "scan-metrics": {
      "total-planning-duration": 100,
      "result-data-files": 5,
      "result-delete-files": 0
    }
  }'

Status Codes

Success

  • 200 OK - Request successful with response body
  • 204 No Content - Request successful without response body
  • 304 Not Modified - Table metadata unchanged (with If-None-Match)

Client Errors

  • 400 Bad Request - Invalid request format
  • 401 Unauthorized - Authentication required
  • 403 Forbidden - Not authorized
  • 404 Not Found - Table or namespace does not exist
  • 406 Not Acceptable - Operation not supported
  • 409 Conflict - Table already exists or commit requirements failed
  • 419 Authentication Timeout - Authentication expired

Server Errors

  • 500 Internal Server Error - Commit state unknown
  • 502 Bad Gateway - Gateway error, commit state unknown
  • 503 Service Unavailable - Service temporarily unavailable
  • 504 Gateway Timeout - Timeout, commit state unknown

Common Patterns

Staged Table Creation (CTAS)

# 1. Stage create (don't commit yet)
curl -X POST ".../namespaces/accounting/tables" \
  -d '{
    "name": "new_table",
    "schema": {...},
    "stage-create": true
  }'

# Returns metadata without creating table

# 2. Write data and commit via update
curl -X POST ".../namespaces/accounting/tables/new_table" \
  -d '{
    "requirements": [{"type": "assert-create"}],
    "updates": [
      {"action": "add-schema", ...},
      {"action": "append", ...}
    ]
  }'

Optimistic Concurrency Control

# Load table
curl -X GET ".../tables/invoices"
# Note current snapshot ID: 12345

# Commit with requirement
curl -X POST ".../tables/invoices" \
  -d '{
    "requirements": [
      {"type": "assert-ref-snapshot-id", "ref": "main", "snapshot-id": 12345}
    ],
    "updates": [...]
  }'

# Returns 409 if another commit happened first

Using ETags

# First load
curl -X GET ".../tables/invoices"
# Response includes: ETag: "abc123"

# Subsequent load
curl -X GET ".../tables/invoices" \
  -H "If-None-Match: abc123"
# Returns 304 if unchanged, 200 with new data if changed

Build docs developers (and LLMs) love