Opening IO Gateway

Reference

API keys

Use when
Client API access
Updated
September 4, 2026

Managed API keys restrict clients by provider and account. Add per-request input caps, legacy input budgets, or independent renewable request and token quotas. Rules and usage are persisted in SQLite across restarts.

API key settings showing whole-key, provider-level, and account-level input-token controls.
Managed keys combine provider/account access with per-request input caps before upstream dispatch.

Access model

  • Provider Allow one or more upstream providers such as Claude, Gemini, or Codex.
  • Account Within an allowed provider, allow every account or selected accounts only.
  • Custom models A ctm: request is authorized against each resolved target's provider and account. There is no model-name or alias-specific allow-list.

Create a managed key

  1. 1
    Open API Keys in the dashboard.

    Use an authenticated operator session.

  2. 2
    Choose route scope.

    Select providers and, for each provider, every account or selected accounts.

  3. 3
    Set input controls.

    Set a per-request input cap at whole-key, provider, or account level; optionally set a whole-key cumulative input-token budget.

  4. 4
    Test with the client key.

    Send a request with the generated key and verify usage history.

Input controls

LimitMeaning
max_estimated_input_tokens_per_requestA positive maximum for estimated input tokens in one request. Set it at whole-key, provider, or account level; the smallest matching cap applies. Omit it for no per-request cap.
prompt_token_limitDeprecated input alias for max_estimated_input_tokens_per_request, retained for migration.
input_token_budgetOptional whole-key cumulative input-token control: {"limit": positive_integer, "period": "lifetime" | "calendar_month"}. It does not cap output tokens or monetary cost.
Scope allow-listProviders and accounts this key can call; it is not a model or alias allow-list.

A per-request cap is a guardrail, not a spending counter. Use input_token_budget when cumulative input-token usage needs a lifetime or calendar-month boundary.

Neither legacy input control is a request-count quota. Cap-only keys can make repeated requests that each fit their cap. Legacy budget estimates are conservative, not exact provider billing counts; each upstream retry or fallback needs its own reservation, and settlement retains at least that amount.

Renewable request and token quotas

Set access.quota to a timezone (default UTC) and a rules array. Each rule contains metric, period, and a positive integer limit. Periods are daily, weekly, or monthly. Multiple rules apply atomically.

{"all":true,"quota":{"timezone":"Asia/Jakarta","rules":[{"metric":"requests","period":"daily","limit":100},{"metric":"input_tokens","period":"weekly","limit":100000},{"metric":"output_tokens","period":"monthly","limit":50000}]}}

Metrics: requests, input_tokens, uncached_input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, and cache_tokens. Input includes cached input; output includes reasoning. Do not add those subsets again to token totals. Missing provider usage is unknown, not zero.

The first accepted generation starts the common anchor. Daily is 24 hours; weekly is 168 hours; monthly follows the original calendar date/time in the chosen timezone, clamping short months. January 31 renews February 28/29 then March 31. Creation, rejected requests, catalog queries, inactivity, and server restarts do not reset usage or move an established anchor.

One admitted client generation consumes one request; retries/fallbacks consume additional tokens, not another logical request. All dimensions are reserved before upstream dispatch and settled to trustworthy actual usage. Interrupted or missing reports retain uncertain conservative charges. Requests-per-day is not a burst/concurrency rate limiter.

Use Add quota rule in the dashboard. Inspect confirmed, reserved, uncertain, and remaining amounts through GET /admin/api-keys/quotas?id=KEY_ID or iogw keys quotas --id KEY_ID. Exhaustion returns protocol-native 429 quota_exceeded with renewal/retry headers. Ordinary allowance edits preserve balances; activated schedule changes are rejected instead of silently resetting them.

Dashboard balances refresh after managed-key Test API calls and every 10 seconds while Settings is open. These read-only refreshes preserve unsaved policy edits and account selections. If a per-key accounting summary fails, /admin/api-keys/quotas returns 503 with ok: false, retaining available summaries and an {"error":true} entry for each failed key. Unavailable accounting never means zero usage or a renewed allowance.

Renewable quota limits support positive signed-64-bit integers through 9223372036854775807. The dashboard safely edits integers only through 9007199254740991; it refuses to edit a policy with larger limits instead of rounding or removing them. Use iogw keys update KEY_ID --access-json @access.json or the admin API for those policies, and iogw keys quotas --id KEY_ID or the API for exact large balances.

Admin create/update requests reject unknown fields in the outer payload and access, provider, account-limit, input-budget, and quota objects. Typos such as acess or quotas cannot silently create an unlimited key. The canonical cap name and deprecated prompt_token_limit alias remain accepted. An empty create payload deliberately creates an unrestricted key; updates require an access object. Persisted legacy metadata remains compatible with migration.

Strict provider capability checks

Set a small explicit output maximum for output quotas. A provider/model without a defensible bound is rejected before dispatch with quota_measurement_required; Codex, Grok, and native MiniMax Responses strict output quotas are currently unsupported. Unknown usage can reduce usable allowance conservatively. Request-only quotas do not require token measurement.

Restart-safe accounting

Managed key authority and quota ledgers live in <auth_dir>/api-key-policy.sqlite3. Legacy JSON is imported with a private recovery backup and an old-binary migration sentinel. Preserve the database, its identity file, and the persistent local volume. Missing or damaged established accounting fails closed; a legacy budget whose accounting database is missing cannot be migrated to a fresh allowance. Pin an explicit persistent auth_dir before upgrading.

io-gateway --config /absolute/config.json --backup-policy /backups/new-policy-snapshot

This command creates a consistent private SQLite snapshot with matching identity metadata and exits. The destination must be new; provider credentials, configuration and reporting history need separate backups. Copying just a live main database can lose committed WAL data. Restoring an old backup requires reconciling the missing usage interval.

Keys with input controls reject unmeasurable media, encrypted or retained context, and provider-hosted retrieval or execution tools with 400 prompt_measurement_required. Ordinary function definitions and JSON schemas remain measurable. Policy history includes dispatches and outcomes for cap-only keys as well as budgeted keys.

Operational advice

Prefer managed keys for clients

Use managed keys instead of the broad shared proxy key when exposing IO Gateway to applications or users.