This document provides practical curl examples for all Pangolin API endpoints.
Note: For Iceberg REST API endpoints (
/v1/*), refer to the Apache Iceberg REST Catalog specification.
- Authentication
- Tenant Management
- Warehouse Management
- Catalog Management
- User Management
- Credential Vending
- Federated Catalogs
- Service Users
- Roles & Permissions
- OAuth
- Branch Operations
- Tag Operations
- Merge Operations & Conflict Resolution
- Business Metadata & Access Requests
- Audit Logs
- Token Management (Admin)
- System Configuration (Admin)
- Federated Catalog Operations
- Data Explorer
- Search & Optimization
# Set environment variable
export PANGOLIN_NO_AUTH=true
# No authentication headers needed
curl http://localhost:8080/api/v1/tenants# Login to get JWT token
curl -X POST http://localhost:8080/api/v1/users/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "password"
}'
# Use token in subsequent requests
export TOKEN="eyJhbGciOiJIUzI1NiIs..."
curl http://localhost:8080/api/v1/tenants \
-H "Authorization: Bearer $TOKEN"# Generate token for automation/scripts
curl -X POST http://localhost:8080/api/v1/tokens \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "550e8400-e29b-41d4-a716-446655440000",
"username": "automation-user",
"expires_in_hours": 720
}'Response:
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-01-17T10:00:00Z"
}# Revoke your current token
curl -X POST http://localhost:8080/api/v1/auth/revoke \
-H "Authorization: Bearer $TOKEN"# Use API key header
export API_KEY="pgl_key_abc123..."
curl http://localhost:8080/api/v1/catalogs \
-H "X-API-Key: $API_KEY"curl http://localhost:8080/api/v1/tenants \
-H "Authorization: Bearer $TOKEN"Response:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "acme-corp",
"properties": {},
"created_at": "2025-12-14T10:00:00Z"
}
]curl -X POST http://localhost:8080/api/v1/tenants \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "new-tenant",
"properties": {
"department": "analytics",
"owner": "data-team"
}
}'curl http://localhost:8080/api/v1/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TOKEN"curl -X PUT http://localhost:8080/api/v1/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "updated-tenant-name",
"properties": {
"department": "data-engineering"
}
}'curl -X DELETE http://localhost:8080/api/v1/tenants/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "s3-warehouse",
"use_sts": false,
"storage_config": {
"type": "s3",
"bucket": "my-data-bucket",
"region": "us-east-1",
"access_key_id": "AKIAIOSFODNN7EXAMPLE",
"secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"endpoint": "http://localhost:9000"
}
}'curl -X POST http://localhost:8080/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "s3-sts-warehouse",
"use_sts": true,
"storage_config": {
"type": "s3",
"bucket": "my-data-bucket",
"region": "us-east-1",
"role_arn": "arn:aws:iam::123456789:role/DataAccess",
"external_id": "optional-external-id"
}
}'curl -X POST http://localhost:8080/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "azure-warehouse",
"use_sts": true,
"storage_config": {
"type": "azure",
"tenant_id": "your-azure-tenant-id",
"client_id": "your-azure-client-id",
"client_secret": "your-azure-client-secret",
"account_name": "mystorageaccount",
"container": "data"
}
}'curl -X POST http://localhost:8080/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "gcp-warehouse",
"use_sts": true,
"storage_config": {
"type": "gcs",
"service_account_key": "{\"type\":\"service_account\",\"project_id\":\"my-project\",...}",
"project_id": "my-project",
"bucket": "my-bucket"
}
}'curl http://localhost:8080/api/v1/warehouses/s3-warehouse \
-H "Authorization: Bearer $TOKEN"curl -X PUT http://localhost:8080/api/v1/warehouses/s3-warehouse \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"use_sts": true,
"storage_config": {
"role_arn": "arn:aws:iam::123456789:role/NewRole"
}
}'curl -X DELETE http://localhost:8080/api/v1/warehouses/s3-warehouse \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/catalogs \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/catalogs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "production",
"warehouse_name": "s3-warehouse",
"storage_location": "s3://my-bucket/warehouse",
"properties": {
"owner": "data-team"
}
}'curl http://localhost:8080/api/v1/catalogs/production \
-H "Authorization: Bearer $TOKEN"curl -X PUT http://localhost:8080/api/v1/catalogs/production \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"warehouse_name": "new-warehouse",
"properties": {
"environment": "production"
}
}'curl -X DELETE http://localhost:8080/api/v1/catalogs/production \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/users \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "john.doe",
"email": "john@example.com",
"password": "secure-password",
"tenant_id": "550e8400-e29b-41d4-a716-446655440000"
}'curl http://localhost:8080/api/v1/users/USER_ID \
-H "Authorization: Bearer $TOKEN"curl -X PUT http://localhost:8080/api/v1/users/USER_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"email": "newemail@example.com"
}'curl -X DELETE http://localhost:8080/api/v1/users/USER_ID \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/v1/production/namespaces/db/tables/users/credentials \
-H "Authorization: Bearer $TOKEN"Response:
{
"storage-credentials": [
{
"prefix": "s3://my-bucket/warehouse/",
"config": {
"access-key": "ASIA...",
"secret-key": "...",
"session-token": "...",
"expiration": "2025-12-14T17:00:00Z",
"s3.region": "us-east-1"
}
}
]
}curl http://localhost:8080/v1/production/namespaces/db/tables/users/credentials \
-H "Authorization: Bearer $TOKEN"Response:
{
"storage-credentials": [
{
"prefix": "abfss://data@mystorageaccount.dfs.core.windows.net/",
"config": {
"adls.auth.type": "OAuth2",
"adls.oauth2.token": "eyJ0eXAiOiJKV1QiLCJhbGci..."
}
}
]
}curl http://localhost:8080/api/v1/federated-catalogs \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/federated-catalogs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "partner-catalog",
"config": {
"properties": {
"uri": "https://partner.example.com",
"token": "partner-api-token"
}
}
}'curl http://localhost:8080/api/v1/federated-catalogs/partner-catalog \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/federated-catalogs/partner-catalog/test \
-H "Authorization: Bearer $TOKEN"curl -X DELETE http://localhost:8080/api/v1/federated-catalogs/partner-catalog \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/service-users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-cd-pipeline",
"description": "Service user for CI/CD automation",
"role": "TenantUser",
"expires_in_days": 30
}'Response:
{
"id": "...",
"name": "ci-cd-pipeline",
"api_key": "pgl_key_abc123...",
"created_at": "2025-12-14T10:00:00Z",
"expires_at": "2026-12-31T23:59:59Z"
}Important: Save the
api_key- it's only shown once!
curl http://localhost:8080/api/v1/service-users \
-H "Authorization: Bearer $TOKEN"curl -X DELETE http://localhost:8080/api/v1/service-users/SERVICE_USER_ID \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/roles \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/roles \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "DataEngineer",
"description": "Can manage tables and schemas",
"permissions": ["read", "write", "create"]
}'curl http://localhost:8080/api/v1/permissions \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/permissions \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user-id": "USER_ID",
"scope": {
"type": "catalog",
"catalog-id": "550e8400-e29b-41d4-a716-446655440000"
},
"actions": ["Read", "Write"]
}'curl -X DELETE http://localhost:8080/api/v1/permissions/PERMISSION_ID \
-H "Authorization: Bearer $TOKEN"# Open in browser or redirect
curl http://localhost:8080/oauth/authorize/google# Open in browser or redirect
curl http://localhost:8080/oauth/authorize/githubNote: OAuth flows require browser interaction. The callback endpoint
/oauth/callback/{provider}is handled automatically.
# Set base URL and token
export BASE_URL="http://localhost:8080"
export TOKEN="your-jwt-token"
# Create tenant
TENANT_RESPONSE=$(curl -s -X POST $BASE_URL/api/v1/tenants \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"acme-corp"}')
TENANT_ID=$(echo $TENANT_RESPONSE | jq -r '.id')
# Create warehouse
curl -X POST $BASE_URL/api/v1/warehouses \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name":"s3-warehouse",
"use_sts":true,
"storage_config":{
"type":"s3",
"bucket":"my-bucket",
"region":"us-east-1",
"role_arn":"arn:aws:iam::123:role/DataAccess"
}
}'
# Create catalog
curl -X POST $BASE_URL/api/v1/catalogs \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name":"production",
"warehouse_name":"s3-warehouse"
}'
# Create namespace (Iceberg REST API)
curl -X POST $BASE_URL/v1/production/namespaces \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"namespace":["analytics"]
}'
echo "✅ Environment created successfully!"401 Unauthorized:
{
"error": "Unauthorized",
"message": "Invalid or missing authentication token"
}404 Not Found:
{
"error": "Not Found",
"message": "Warehouse 'nonexistent' not found"
}500 Internal Server Error:
{
"error": "Internal Server Error",
"message": "Failed to connect to database"
}-
Use jq for JSON parsing:
curl http://localhost:8080/api/v1/catalogs | jq '.[] | .name'
-
Save tokens in environment variables:
export TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{"username":"admin","password":"password"}' | jq -r '.token')
-
Use
-vfor debugging:curl -v http://localhost:8080/api/v1/tenants
-
Pretty print JSON responses:
curl http://localhost:8080/api/v1/catalogs | jq '.'
- OpenAPI Specification - Complete API schema
- Apache Iceberg REST Spec - Iceberg endpoints
- Authentication Guide - Authentication setup
- Getting Started - Quick start guide
curl http://localhost:8080/api/v1/branches \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/branches \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "dev",
"catalog_name": "production",
"source_branch": "main"
}'curl http://localhost:8080/api/v1/branches/dev \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/branches/dev/commits \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/branches/merge \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source_branch": "dev",
"target_branch": "main",
"catalog_name": "production"
}'curl http://localhost:8080/api/v1/tags \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/tags \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "v1.0.0",
"catalog_name": "production",
"commit_id": "abc123..."
}'curl -X DELETE http://localhost:8080/api/v1/tags/v1.0.0 \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/catalogs/production/merge-operations \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/merge-operations/OPERATION_ID \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/merge-operations/OPERATION_ID/conflicts \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/conflicts/CONFLICT_ID/resolve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"strategy": "TakeSource"
}'curl -X POST http://localhost:8080/api/v1/merge-operations/OPERATION_ID/complete \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/merge-operations/OPERATION_ID/abort \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/assets/ASSET_ID/metadata \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"owner": "data-team",
"classification": "PII",
"tags": ["customer", "sensitive"]
}'curl http://localhost:8080/api/v1/assets/ASSET_ID/metadata \
-H "Authorization: Bearer $TOKEN"curl http://localhost:8080/api/v1/assets/search?q=customer \
-H "Authorization: Bearer $TOKEN"curl -X POST http://localhost:8080/api/v1/assets/ASSET_ID/request-access \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Need access for analytics project"
}'curl http://localhost:8080/api/v1/access-requests \
-H "Authorization: Bearer $TOKEN"curl -X PUT http://localhost:8080/api/v1/access-requests/REQUEST_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "approved"
}'curl http://localhost:8080/api/v1/audit \
-H "Authorization: Bearer $TOKEN"Response:
[
{
"id": "...",
"timestamp": "2025-12-18T10:00:00Z",
"user_id": "...",
"action": "table.create",
"resource": "production.analytics.users",
"details": {}
}
]# List all tokens for a specific user (admin only)
curl http://localhost:8080/api/v1/users/USER_ID/tokens \
-H "Authorization: Bearer $TOKEN"Response:
[
{
"id": "token-uuid-123",
"user_id": "user-uuid-456",
"created_at": "2025-12-19T10:00:00Z",
"expires_at": "2026-01-19T10:00:00Z",
"is_valid": true
}
]# Delete a specific token by ID (admin only)
curl -X DELETE http://localhost:8080/api/v1/tokens/TOKEN_ID \
-H "Authorization: Bearer $TOKEN"# Get all system configuration settings (admin only)
curl http://localhost:8080/api/v1/config/settings \
-H "Authorization: Bearer $TOKEN"Response:
{
"allow_public_signup": false,
"default_retention_days": 30,
"default_warehouse_bucket": "my-default-bucket",
"smtp_host": "smtp.example.com",
"smtp_port": 587,
"smtp_user": "noreply@example.com",
"smtp_password": "***"
}# Update system configuration settings (admin only)
curl -X PUT http://localhost:8080/api/v1/config/settings \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"allow_public_signup": true,
"default_retention_days": 90,
"smtp_host": "smtp.newprovider.com"
}'# Trigger immediate metadata sync for federated catalog
curl -X POST http://localhost:8080/api/v1/federated-catalogs/partner-catalog/sync \
-H "Authorization: Bearer $TOKEN"Response:
{
"status": "Sync triggered",
"catalog_name": "partner-catalog",
"triggered_at": "2025-12-19T10:00:00Z"
}# Get sync statistics and status for federated catalog
curl http://localhost:8080/api/v1/federated-catalogs/partner-catalog/stats \
-H "Authorization: Bearer $TOKEN"Response:
{
"catalog_name": "partner-catalog",
"last_synced_at": "2025-12-19T09:00:00Z",
"sync_status": "success",
"tables_synced": 42,
"namespaces_synced": 5,
"last_error": null,
"next_scheduled_sync": "2025-12-19T12:00:00Z"
}# Get hierarchical namespace tree structure for a catalog
curl http://localhost:8080/api/v1/catalogs/production/namespaces/tree \
-H "Authorization: Bearer $TOKEN"Response:
{
"root": [
{
"name": ["analytics"],
"children": [
{
"name": ["analytics", "sales"],
"children": []
},
{
"name": ["analytics", "marketing"],
"children": []
}
]
},
{
"name": ["staging"],
"children": []
}
]
}# 1. List all tokens for a user (admin)
curl http://localhost:8080/api/v1/users/$USER_ID/tokens \
-H "Authorization: Bearer $TOKEN"
# 2. Delete a specific token
curl -X DELETE http://localhost:8080/api/v1/tokens/$TOKEN_ID \
-H "Authorization: Bearer $TOKEN"# 1. Get current settings
SETTINGS=$(curl -s http://localhost:8080/api/v1/config/settings \
-H "Authorization: Bearer $TOKEN")
echo $SETTINGS | jq '.'
# 2. Update specific settings
curl -X PUT http://localhost:8080/api/v1/config/settings \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"allow_public_signup": true,
"default_retention_days": 60
}'# 1. Check sync stats
curl http://localhost:8080/api/v1/federated-catalogs/partner-catalog/stats \
-H "Authorization: Bearer $TOKEN" | jq '.'
# 2. Trigger manual sync if needed
curl -X POST http://localhost:8080/api/v1/federated-catalogs/partner-catalog/sync \
-H "Authorization: Bearer $TOKEN"
# 3. Wait and check stats again
sleep 30
curl http://localhost:8080/api/v1/federated-catalogs/partner-catalog/stats \
-H "Authorization: Bearer $TOKEN" | jq '.last_synced_at'Search across catalogs, namespaces, and tables.
curl "http://localhost:8080/api/v1/search?q=sales&tenant_id=550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer $TOKEN"Check if a name is valid and available.
curl -X POST http://localhost:8080/api/v1/validate/names \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"resource_type": "catalog",
"names": ["new_catalog_v2"]
}'
### Bulk Asset Deletion
```bash
curl -X POST http://localhost:8080/api/v1/bulk/assets/delete \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"asset_ids": ["uuid-1", "uuid-2"]
}'