Skip to main content

Introduction

The Admin API lets you manage regular organization API keys, inspect organization billing data, and access container-related APIs with an admin API key. Admin API keys are for organizations, not personal accounts.

Common use cases

  • Automating key management: Create, rotate, or delete API keys programmatically, and set expiration dates or token limits based on your business logic.
  • Building custom dashboards: Display usage metrics, cost breakdowns by model, and historical trends using the billing and time-series endpoints.
  • Monitoring usage: Query aggregated or per-key usage statistics to track costs and token consumption.
  • Managing containers programmatically: Create, validate, update, stop, start, and delete containers. Manage org secrets, SSH keys, custom domains, registry credentials, and container grouping from automation.
If you need per-user usage metrics for billing, the recommended approach is to run a proxy server that tracks token counts via response headers — rather than creating a separate API key per user in your system.

Authentication

Admin API keys provide programmatic access to your account resources. Admin keys are prefixed with admin_ and must be included in the Authorization header as a Bearer token.
Need to create an admin API key? Follow our step-by-step guide: Getting a Tinfoil Admin Key
Admin keys provide programmatic access to organization settings, including managing API keys, reading billing data, and administering container resources. Do not share admin keys or expose them in browsers, client-side code, or public repositories. Revoke admin keys when team members with admin access leave your organization.
Authorization: Bearer YOUR_ADMIN_KEY

Available endpoints

This page covers the following endpoints:

API key management

  • GET /api/keys - List API keys
  • POST /api/keys - Create a new API key
  • POST /api/keys/update - Update an API key name or token cap
  • DELETE /api/keys/:key - Delete an API key

Billing & usage

  • GET /api/billing/usage - Get aggregated usage statistics for all keys
  • POST /api/billing/usage/key - Get usage statistics for a specific key
  • GET /api/billing/time-series - Get time series data
  • GET /api/billing/transactions - Get transaction history

Container endpoints

  • Lifecycle & deployment
    • POST /api/containers/validate-name - Validate a container name or custom domain before deploy
    • POST /api/containers/validate - Validate tinfoil-config.yml before deploy
    • GET /api/containers/hosts - List hosts available to the organization
    • GET /api/containers - List containers
    • GET /api/containers/:id - Get a specific container
    • POST /api/containers - Create a container
    • POST /api/containers/:id/relaunch - Relaunch a running or failed container
    • POST /api/containers/:id/stop - Stop a running container
    • POST /api/containers/:id/start - Start a stopped container
    • DELETE /api/containers/:id - Delete a container
    • GET /api/containers/:id/update - Get in-progress update status
    • POST /api/containers/:id/update/cancel - Cancel an in-progress update
    • POST /api/containers/:id/auto-update - Toggle auto-update
    • POST /api/containers/:id/github-connection - Toggle GitHub App connection
    • GET /api/containers/:id/metrics - Get resource metrics
  • Organization
    • PUT /api/containers/:id/group - Move a container into or out of a group
    • PUT /api/containers/reorder - Reorder containers
    • PUT /api/containers/groups/rename - Rename a group
    • PUT /api/containers/groups/reorder - Reorder groups
    • DELETE /api/containers/groups/:name - Delete a group
  • Related resources
    • GET /api/secrets - List org secrets
    • POST /api/secrets - Create a secret
    • GET /api/secrets/:name - Get a secret’s metadata
    • PUT /api/secrets/:name - Update a secret
    • DELETE /api/secrets/:name - Delete a secret
    • GET /api/ssh-keys - List org SSH keys
    • POST /api/ssh-keys - Create an SSH key
    • DELETE /api/ssh-keys/:name - Delete an SSH key
    • GET /api/domains - List custom domains
    • POST /api/domains - Add a domain
    • POST /api/domains/:domain/verify - Verify a domain
    • DELETE /api/domains/:domain - Delete a domain
    • GET /api/registry-credentials - List private registry credential status
    • PUT /api/registry-credentials/:registry - Create or update private registry credentials
    • DELETE /api/registry-credentials/:registry - Delete private registry credentials

API Key Management

List API Keys

GET /api/keys
endpoint
Returns all regular (non-admin) API keys in your organization. Keys you created are returned in full. Keys created by other members are masked (for example, tk_12345***).

Example Request

curl "https://api.tinfoil.sh/api/keys"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

[
  {
    "key": "tk_your_full_key_value_here",
    "name": "Production Key",
    "disabled": false,
    "expires_at": "2026-12-31T23:59:59Z",
    "max_tokens": 1000000,
    "metadata": {
      "environment": "production"
    },
    "tokens_used": 450000,
    "input_tokens_used": 250000,
    "output_tokens_used": 200000,
    "request_count": 1200,
    "is_owner": true,
    "created_at": "2026-04-01T00:00:00Z",
    "last_used_at": "2026-04-09T12:34:56Z"
  },
  {
    "key": "tk_abcde**************************",
    "name": "Staging Key",
    "disabled": false,
    "expires_at": null,
    "max_tokens": null,
    "metadata": {},
    "tokens_used": 0,
    "input_tokens_used": 0,
    "output_tokens_used": 0,
    "request_count": 0,
    "is_owner": false,
    "created_at": "2026-04-02T00:00:00Z",
    "last_used_at": "2026-04-08T09:00:00Z"
  }
]

Create API Key

POST /api/keys
endpoint
Creates a new regular API key for your organization. Requires active token billing for the organization.

Request Body

name
string
required
Name for the API key. Must contain only alphanumeric characters, hyphens, underscores, spaces, and periods.
expires_at
datetime
ISO 8601 timestamp when the key should expire. If not provided, the key doesn’t expire.
max_tokens
integer
Maximum number of tokens this key can use. If not provided, no limit is enforced.
metadata
object
Custom metadata to attach to the key. Maximum size: 5KB.

Example Request

curl -X POST https://api.tinfoil.sh/api/keys   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{
    "name": "Production API Key",
    "expires_at": "2026-12-31T23:59:59Z",
    "max_tokens": 1000000,
    "metadata": {
      "environment": "production",
      "team": "backend"
    }
  }'

Response

{
  "key": "tk_your_new_key_value_here",
  "name": "Production API Key",
  "disabled": false,
  "expires_at": "2026-12-31T23:59:59Z",
  "max_tokens": 1000000,
  "metadata": {
    "environment": "production",
    "team": "backend"
  },
  "tokens_used": 0,
  "input_tokens_used": 0,
  "output_tokens_used": 0,
  "request_count": 0,
  "is_owner": true,
  "created_at": "2026-04-09T00:00:00Z",
  "last_used_at": null
}

Update API Key

POST /api/keys/update
endpoint
Updates an existing regular API key in your organization. You can update any non-admin key in the organization, provided you have the full key value.

Request Body

key
string
required
The API key value to update, as returned by GET /api/keys.
name
string
New display name for the API key.
max_tokens
integer
New token cap for the key. Set this to 0 to clear the existing cap.

Example Request

curl -X POST https://api.tinfoil.sh/api/keys/update   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{
    "key": "tk_your_full_key_value_here",
    "name": "Staging API Key",
    "max_tokens": 0
  }'

Response

{
  "message": "API key updated"
}

Delete API Key

DELETE /api/keys/:key
endpoint
Deletes a regular API key in your organization. You can delete any non-admin key, provided you have the full key value.

Path Parameters

key
string
required
The API key value to delete (for example, tk_your_full_key_value_here).

Example Request

curl -X DELETE https://api.tinfoil.sh/api/keys/tk_your_full_key_value_here   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

{
  "message": "API key deleted"
}

Billing & Usage

Get Usage Statistics

GET /api/billing/usage
endpoint
Retrieves aggregated usage statistics for your organization for the specified time period.

Query Parameters

time
string
Time period for usage statistics. If omitted, returns all-time usage. Valid values:
  • 5m - Last 5 minutes
  • 15m - Last 15 minutes
  • 30m - Last 30 minutes
  • 1h - Last hour
  • 24h - Last 24 hours
  • 7d - Last 7 days
  • 30d - Last 30 days
  • 60d - Last 60 days
  • 90d - Last 90 days

Example Request

curl "https://api.tinfoil.sh/api/billing/usage?time=7d"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

{
  "tokens": 1500000,
  "input_tokens": 800000,
  "output_tokens": 700000,
  "requests": 3200,
  "cost": 15.00,
  "keys": {
    "Production Key": {
      "total_tokens": 1000000,
      "total_input_tokens": 600000,
      "total_output_tokens": 400000,
      "total_requests": 2000,
      "cost": 10.00,
      "models": {
        "kimi-k2-5": {
          "tokens": 600000,
          "input_tokens": 350000,
          "output_tokens": 250000,
          "requests": 1200,
          "cost": 6.00
        },
        "gpt-oss-120b": {
          "tokens": 400000,
          "input_tokens": 250000,
          "output_tokens": 150000,
          "requests": 800,
          "cost": 4.00
        }
      }
    },
    "Development Key": {
      "total_tokens": 500000,
      "total_input_tokens": 200000,
      "total_output_tokens": 300000,
      "total_requests": 1200,
      "cost": 5.00,
      "models": {
        "llama3-3-70b": {
          "tokens": 500000,
          "input_tokens": 200000,
          "output_tokens": 300000,
          "requests": 1200,
          "cost": 5.00
        }
      }
    }
  }
}
The keys object is grouped by API key name.

Get Usage by Key

POST /api/billing/usage/key
endpoint
Retrieves usage statistics for a specific regular API key in your organization.

Query Parameters

time
string
Time period for usage statistics. If omitted, returns all-time usage. Valid values:
  • 5m - Last 5 minutes
  • 15m - Last 15 minutes
  • 30m - Last 30 minutes
  • 1h - Last hour
  • 24h - Last 24 hours
  • 7d - Last 7 days
  • 30d - Last 30 days
  • 60d - Last 60 days
  • 90d - Last 90 days

Request Body

key
string
required
The API key value to query (for example, tk_your_full_key_value_here), as returned by GET /api/keys.

Example Request

curl -X POST "https://api.tinfoil.sh/api/billing/usage/key?time=7d"   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{"key": "tk_your_full_key_value_here"}'

Response

{
  "prompt_tokens": 800000,
  "completion_tokens": 700000,
  "requests": 3200,
  "cost": 15.00
}

Get Time Series Data

GET /api/billing/time-series
endpoint
Retrieves time-series usage data for your organization over the specified period.

Query Parameters

time
string
default:"24h"
Time period for the time series. Valid values:
  • 5m - Last 5 minutes
  • 15m - Last 15 minutes
  • 30m - Last 30 minutes
  • 1h - Last hour
  • 24h - Last 24 hours
  • 7d - Last 7 days
  • 30d - Last 30 days
  • 60d - Last 60 days
  • 90d - Last 90 days
The response interval is fixed per window: 5m5s, 15m15s, 30m30s, 1h1m, 24h15m, 7d2h, 30d8h, and 60d/90d24h. Empty buckets are included as zero-value data points.

Example Request

curl "https://api.tinfoil.sh/api/billing/time-series?time=24h"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

{
  "data_points": [
    {
      "time": "2026-04-08T12:00:00Z",
      "tokens": 50000,
      "input_tokens": 30000,
      "output_tokens": 20000,
      "requests": 100,
      "models": {
        "kimi-k2-5": {
          "tokens": 30000,
          "input_tokens": 18000,
          "output_tokens": 12000,
          "requests": 60
        },
        "llama3-3-70b": {
          "tokens": 20000,
          "input_tokens": 12000,
          "output_tokens": 8000,
          "requests": 40
        }
      }
    },
    {
      "time": "2026-04-08T12:15:00Z",
      "tokens": 75000,
      "input_tokens": 45000,
      "output_tokens": 30000,
      "requests": 150,
      "models": {
        "kimi-k2-5": {
          "tokens": 75000,
          "input_tokens": 45000,
          "output_tokens": 30000,
          "requests": 150
        }
      }
    }
  ],
  "interval": "15m0s"
}

Get Transaction History

GET /api/billing/transactions
endpoint
Retrieves invoice and standalone charge history for your organization.
Viewing transaction history requires organization admin access. If the organization does not have a Stripe customer yet, the response is:
{
  "transactions": []
}

Example Request

curl "https://api.tinfoil.sh/api/billing/transactions"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

{
  "transactions": [
    {
      "id": "in_1234567890",
      "date": "2024-01-01T00:00:00Z",
      "type": "Invoice",
      "description": "Monthly subscription",
      "amount": 99.00,
      "status": "completed",
      "invoice_url": "https://invoice.stripe.com/i/..."
    },
    {
      "id": "ch_0987654321",
      "date": "2024-01-15T12:30:00Z",
      "type": "Charge",
      "description": "API Usage",
      "amount": 25.50,
      "status": "completed"
    }
  ]
}

Containers

Admin API keys can access the same container APIs as a browser session, as long as the key belongs to the target organization.
Create, start, and relaunch operations require an active container subscription. Read-only endpoints and cleanup operations such as list, get, stop, and delete do not require an active subscription.
Private registry endpoints require private registry access to be enabled for the organization.

Lifecycle & Deployment

Validate Container Name

POST /api/containers/validate-name
endpoint
Checks whether a container name is valid and available for the current organization. You can also validate a custom domain before creating or relaunching a container.

Request Body

name
string
required
Container name. Must be lowercase alphanumeric with hyphens, max 64 characters.
debug
boolean
Whether to validate the name for debug mode.
custom_domain
string
Custom domain to validate.
relaunch_container_id
string
Existing container UUID when validating a relaunch that keeps the same custom domain.

Example Request

curl -X POST "https://api.tinfoil.sh/api/containers/validate-name"   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{
    "name": "my-app",
    "debug": false,
    "custom_domain": "api.example.com"
  }'

Response

{
  "available": true,
  "name": "my-app"
}

Validate Container Config

POST /api/containers/validate
endpoint
Validates the tinfoil-config.yml in a repository tag before create, replace, or relaunch.

Request Body

repo
string
required
GitHub repository in owner/repo format.
tag
string
required
Git tag to validate.
relaunch_container_id
string
Existing container UUID. When present, instance-limit checks are skipped for relaunch validation.
replace_container_id
string
Existing container UUID. When present, instance-limit checks are skipped for replace validation.

List Hosts

GET /api/containers/hosts
endpoint
Returns the container hosts available to the organization, including the default host and the GPU values available on each host.

Response

[
  {
    "name": "default-host",
    "is_default": true,
    "available_gpu_values": [1, 2, 4]
  }
]

List Containers

GET /api/containers
endpoint
Returns all containers in your organization. Responses may also include ssh_port, host_name, host_gpu_type, and host_cpu_type when available.

Example Request

curl "https://api.tinfoil.sh/api/containers"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Response

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "my-app",
    "repo": "myorg/my-app",
    "status": "ready",
    "domain": "my-app.myorg.tinfoil.dev",
    "current_tag": "v1.2.0",
    "cpus": 2,
    "gpus": 0,
    "memory_mb": 4096,
    "debug": false,
    "created_at": "2026-04-01T00:00:00Z"
  }
]

Get Container

GET /api/containers/:id
endpoint
Returns details for a specific container.

Path Parameters

id
string
required
The container UUID.

Example Request

curl "https://api.tinfoil.sh/api/containers/550e8400-e29b-41d4-a716-446655440000"   -H "Authorization: Bearer YOUR_ADMIN_KEY"

Create Container

POST /api/containers
endpoint
Creates and deploys a new container. The repository must contain a tinfoil-config.yml at the specified tag.

Request Body

name
string
required
Container name. Must be lowercase alphanumeric with hyphens.
repo
string
required
GitHub repository in owner/repo format.
tag
string
required
Git tag to deploy. The tag must have a published GitHub release.
variables
object
Environment variables as key-value pairs.
secrets
string[]
Names of existing org secrets to inject.
ssh_keys
string[]
Names of existing org SSH keys to inject.
debug
boolean
Enable debug mode.
docker_log
boolean
Enable docker log capture for the deployment.
gpus
integer
Number of GPUs to allocate. Requires GPU access for the organization.
custom_domain
string
Verified custom domain for the container.
host_name
string
Target host name. Requires target host selection to be enabled for the organization.
replace_container_id
string
Existing container UUID to replace.

Example Request

curl -X POST "https://api.tinfoil.sh/api/containers"   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{
    "name": "my-app",
    "repo": "myorg/my-app",
    "tag": "v1.2.0",
    "variables": {
      "LOG_LEVEL": "info"
    },
    "secrets": ["DATABASE_URL"],
    "debug": false
  }'

Response

Returns the created container object with status deploying. The container transitions to ready once the deployment completes.

Relaunch Container

POST /api/containers/:id/relaunch
endpoint
Relaunches a running or failed container with a new tag, updated configuration, or both. Running single-GPU and CPU-only containers usually use a blue-green deployment flow. Multi-GPU updates use a different flow and cannot always be canceled once started.

Path Parameters

id
string
required
The container UUID.

Request Body

All fields are optional. Omitted fields keep their current values.
tag
string
New git tag to deploy.
variables
object
New environment variables. This replaces the full existing variable set.
secrets
string[]
New secret-name list. This replaces the full existing secret set.
ssh_keys
string[]
New SSH key-name list.
gpus
integer
New GPU count.
debug
boolean
Toggle debug mode.
custom_domain
string
Set or clear a custom domain. Pass an empty string to revert to the auto-generated domain.

Example Request

curl -X POST "https://api.tinfoil.sh/api/containers/550e8400-e29b-41d4-a716-446655440000/relaunch"   -H "Authorization: Bearer YOUR_ADMIN_KEY"   -H "Content-Type: application/json"   -d '{
    "tag": "v1.3.0"
  }'

Stop Container

POST /api/containers/:id/stop
endpoint
Stops a running container. The container record is preserved and can be started again later.

Start Container

POST /api/containers/:id/start
endpoint
Starts a stopped container. You can optionally pass the same body fields as relaunch to update configuration at start time.

Delete Container

DELETE /api/containers/:id
endpoint
Permanently deletes a container and its deployment. Outstanding billing is finalized before deletion.
Returns 204 No Content on success.

Get Update Status

GET /api/containers/:id/update
endpoint
Returns the status of an in-progress relaunch or restart.

Response

{
  "has_update": true,
  "update_deployment_id": "dep_123",
  "update_tag": "v1.3.0",
  "update_status": "deploying"
}
If no update is in progress:
{
  "has_update": false
}

Cancel Update

POST /api/containers/:id/update/cancel
endpoint
Cancels an in-progress update and returns 204 No Content. Multi-GPU updates cannot be canceled once started.

Toggle Auto-Update

POST /api/containers/:id/auto-update
endpoint
Enables or disables auto-update for a GitHub App connected container.

Request Body

auto_update
boolean
required
Whether auto-update should be enabled.

Toggle GitHub App Connection

POST /api/containers/:id/github-connection
endpoint
Sets whether the container is connected to a GitHub App installation for its repo owner.

Request Body

connected
boolean
required
Whether GitHub App connectivity should be enabled.

Get Container Metrics

GET /api/containers/:id/metrics
endpoint
Returns CPU, GPU, and memory utilization time series for a container. The time query parameter defaults to 24h.

Organization

These endpoints are also available to admin API keys:
  • PUT /api/containers/:id/group moves a container into or out of a group with group_name, group_order, and display_order
  • PUT /api/containers/reorder bulk-updates container display order
  • PUT /api/containers/groups/rename renames a group
  • PUT /api/containers/groups/reorder updates group order
  • DELETE /api/containers/groups/:name removes a group and ungroups its containers

Secrets

Org secrets are encrypted values injected into containers at deploy time. Secret names must be UPPER_SNAKE_CASE or kebab-case.

GET /api/secrets
endpoint
Returns all org-level secrets as metadata only. Secret values are never returned.

GET /api/secrets/:name
endpoint
Returns metadata for a single secret, including which containers use it.

POST /api/secrets
endpoint
Creates a new org secret.

Request Body

name
string
required
Secret name.
value
string
required
Secret value.

PUT /api/secrets/:name
endpoint
Updates the value of an existing org secret.

DELETE /api/secrets/:name
endpoint
Deletes an org secret. If the secret is currently used by any container, the API returns 409 Conflict and includes the blocking container names.

SSH Keys

SSH key names must be kebab-case, for example my-deploy-key.

GET /api/ssh-keys
endpoint
Returns all org-level SSH keys.

POST /api/ssh-keys
endpoint
Adds a new org SSH key for debug-mode containers.

Request Body

name
string
required
SSH key name in kebab-case.
public_key
string
required
SSH public key, for example ssh-ed25519 AAAA....

DELETE /api/ssh-keys/:name
endpoint
Deletes an org SSH key. If the key is currently used by any container, the API returns 409 Conflict and includes the blocking container names.

Custom Domains

GET /api/domains
endpoint
Returns all custom domains for the organization, including verification details and which containers use each domain.

POST /api/domains
endpoint
Adds a custom domain for verification and returns the TXT and CNAME records required for setup.

Request Body

domain
string
required
Domain name to register, for example api.example.com.

POST /api/domains/:domain/verify
endpoint
Checks DNS records and updates the domain’s verification state.

DELETE /api/domains/:domain
endpoint
Deletes a custom domain. If the domain is currently used by any container, the API returns 409 Conflict and includes the blocking container names.

Registry Credentials

Private registry credentials are supported for ghcr, gcr, and dockerhub.

GET /api/registry-credentials
endpoint
Returns credential status for each supported registry, including whether credentials exist, whether they are expired, and when they were last updated.

PUT /api/registry-credentials/:registry
endpoint
Creates or updates credentials for a supported registry.

Path Parameters

registry
string
required
Registry identifier: ghcr, gcr, or dockerhub.

Request Body

For ghcr:
{
  "username": "myuser",
  "token": "ghp_xxxxxxxxxxxx"
}
For gcr:
{
  "key": "{...service account json...}"
}
For dockerhub:
{
  "username": "myuser",
  "token": "dckr_pat_xxxxxxxxxxxx"
}

DELETE /api/registry-credentials/:registry
endpoint
Deletes credentials for a supported registry.

Error Responses

Example error response:
{
  "error": "invalid admin API key",
  "code": "UNAUTHORIZED"
}
Common error codes:
CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or expired admin API key
FORBIDDEN403Your admin key no longer has access to this organization or action
BAD_REQUEST400Invalid request parameters
NOT_FOUND404Resource not found, or the referenced API key is not available through this admin key
PAYMENT_REQUIRED402Active subscription required
INTERNAL_ERROR500Server error