Skip to main content
Version: 1.11.0

Iceberg REST API

The Iceberg REST API is the Apache Iceberg REST catalog protocol, served by the Iceberg REST service. Spark, Trino, Flink, PyIceberg and other Iceberg engines use it to list, create, load and commit tables and views. This reference covers the operations the service implements, from the Apache Iceberg 1.11.0 specification.

Base URL​

Every path in this reference is relative to https://{iceberg_host}/iceberg, where {iceberg_host} is the host the service is published on; see HTTPS. Engines take this address as the catalog URI.

The service serves the Iceberg catalogs of one metalake. Each Gravitino catalog is a separate Iceberg REST catalog, selected by the {prefix} in the path. A client finds the prefix by calling GET /v1/config with the catalog name as warehouse; the response returns it in defaults.prefix. A client that names no warehouse gets the service's default catalog.

Read a catalog's configuration
curl -sS -H "Authorization: Bearer $TOKEN" \
"https://{iceberg_host}/iceberg/v1/config?warehouse={catalog}"

Authentication​

Every call needs credentials:

  • A bearer token issued by the identity provider the server is configured for.
  • A user name and password of a local user, sent as HTTP basic credentials.

Each call is checked against the caller's roles in the metalake, and a call the roles do not allow returns HTTP 403; see Privileges.

Credential vending​

A client that sends X-Iceberg-Access-Delegation: vended-credentials when it loads or creates a table receives temporary storage credentials scoped to that table, and an endpoint to refresh them. vended-credentials is the only delegation mode the service supports. See Credential vending.

Example​

The script signs in, reads the catalog's configuration, then creates a namespace and a table, loads the table with vended credentials, and cleans up. It needs curl and jq. Set the variables at the top, and pick one way to sign in.

iceberg-rest-example.sh
#!/usr/bin/env bash
set -euo pipefail

ICEBERG_URI="https://{iceberg_host}/iceberg"
CATALOG="{catalog}"
NAMESPACE="irc_example"
TABLE="orders"
PASSWORD="${PASSWORD:?set PASSWORD first}"

# 1. Sign in. A local user sends basic credentials on every call:
AUTH="Authorization: Basic $(printf '%s:%s' "{user}" "$PASSWORD" | base64)"
# Or request a token from your identity provider with client credentials:
# TOKEN=$(curl -sS -X POST "{token_endpoint}" \
# -d grant_type=client_credentials -d client_id="{client_id}" \
# -d client_secret="$CLIENT_SECRET" -d scope="{scope}" | jq -r .access_token)
# AUTH="Authorization: Bearer $TOKEN"

call() { curl -sS --fail-with-body -H "$AUTH" -H "Content-Type: application/json" "$@"; }

# 2. Read the catalog's configuration and the prefix for later calls.
PREFIX=$(call "$ICEBERG_URI/v1/config?warehouse=$CATALOG" | jq -r .defaults.prefix)
BASE="$ICEBERG_URI/v1/$PREFIX"

# 3. Create a namespace and list the catalog's namespaces.
call -X POST "$BASE/namespaces" -d "{\"namespace\": [\"$NAMESPACE\"]}" | jq .
call "$BASE/namespaces" | jq .namespaces

# 4. Create a table.
call -X POST "$BASE/namespaces/$NAMESPACE/tables" -d "{
\"name\": \"$TABLE\",
\"schema\": {\"type\": \"struct\", \"schema-id\": 0, \"fields\": [
{\"id\": 1, \"name\": \"order_id\", \"type\": \"long\", \"required\": true},
{\"id\": 2, \"name\": \"amount\", \"type\": \"decimal(10,2)\", \"required\": false}
]}
}" | jq -r '.["metadata-location"]'

# 5. List the namespace's tables, then load the table with vended storage credentials.
call "$BASE/namespaces/$NAMESPACE/tables" | jq .identifiers
call -H "X-Iceberg-Access-Delegation: vended-credentials" \
"$BASE/namespaces/$NAMESPACE/tables/$TABLE" | jq '{location: .metadata.location, credentials: (.config | keys)}'

# 6. Refresh the table's storage credentials.
call "$BASE/namespaces/$NAMESPACE/tables/$TABLE/credentials" | jq '.["storage-credentials"][].prefix'

# 7. Clean up: drop the table and its data, then the namespace.
call -X DELETE "$BASE/namespaces/$NAMESPACE/tables/$TABLE?purgeRequested=true"
call -X DELETE "$BASE/namespaces/$NAMESPACE"

The caller needs USE_CATALOG, CREATE_SCHEMA and CREATE_TABLE on the catalog, and owns the namespace and table it creates; see Privileges. A catalog with a table encryption policy that requires a key rejects a create that names none, with HTTP 400 and the reason KEY_REQUIRED. A namespace with more than one level is written with its levels separated by %1F in the path, as in sales%1Feu.

Errors​

A failed call returns an HTTP error status and an Iceberg error body:

Example error response
{
"error": {
"message": "Namespace does not exist: sales",
"type": "NoSuchNamespaceException",
"code": 404
}
}

Operations not served​

The service plans each scan in a single call to POST /v1/{prefix}/namespaces/{namespace}/tables/{table}/plan and returns the whole plan in its response, so it does not serve the calls the specification adds for plans that finish later: GET and DELETE /v1/{prefix}/namespaces/{namespace}/tables/{table}/plan/{plan-id} and POST /v1/{prefix}/namespaces/{namespace}/tables/{table}/tasks. See Scan planning.

The service does not serve POST /v1/oauth/tokens, which the specification deprecates. A client that signs in with a client ID and secret needs the identity provider's token endpoint set explicitly, as oauth2-server-uri in PyIceberg, or it requests a token from this path and fails.

The service also does not serve POST /v1/{prefix}/namespaces/{namespace}/tables/{table}/sign, POST /v1/{prefix}/transactions/commit or POST /v1/{prefix}/namespaces/{namespace}/register-view.

To see every operation a running service supports, call GET /v1/config, which every client calls first anyway; its endpoints field lists them.

License

Apache 2.0