Valta Docs

Proxy API

Two kinds of credential are involved:

CredentialLooks likeUsed for
Valta API keysk_valta_…Managing an agent's provider key and virtual keys (/api/v1/agents/:id/...). Live mode only.
Valta virtual keyvk_live_…Calling the proxy (/v1/chat/completions). Held by the agent. Only works against Valta.

Management routes accept the Valta API key as x-api-key: <key> or Authorization: Bearer <key>. Base URL for management: https://valta.co/api/v1. Base URL for the proxy: https://valta.co/v1.

Provider keys, virtual keys, and Cap limits all belong to one agent (:id). The agent id is any id you use for that agent in Valta — the same one its dashboard page uses (/dashboard/agents/<id>).

Store an OpenAI key

POST /api/v1/agents/:id/provider-keys — requires write.

bash
curl -X POST https://valta.co/api/v1/agents/support-bot/provider-keys \
  -H "x-api-key: $VALTA_API_KEY" -H "Content-Type: application/json" \
  -d '{"provider":"openai","apiKey":"sk-proj-..."}'
json
201
{
  "success": true,
  "providerKey": { "keyId": "pk_…", "provider": "openai", "last4": "a1B2", "createdAt": "2026-09-24T19:55:04.618Z" }
}
  • Encrypted at rest. Only last4 is ever returned.
  • Replaces the agent's previous OpenAI key in the same transaction. The next proxied call uses the new key.
  • Valta doesn't call OpenAI to validate it — an unfunded key saves fine.
  • 400 INVALID_PROVIDER_KEY if it doesn't look like sk-… or is a Valta virtual key. 400 LIVE_MODE_REQUIRED with a test-mode API key.

GET /api/v1/agents/:id/provider-keys — requires read. Returns { success, providerKeys: [{ keyId, provider, last4, createdAt }] }.

Mint a virtual key

POST /api/v1/agents/:id/virtual-keys — requires write. Body: { "name"?: string }.

json
201
{
  "success": true,
  "virtualKey": {
    "keyId": "vk_…",
    "agentId": "support-bot",
    "name": "production",
    "prefix": "vk_live_3f9a1c…",
    "status": "active",
    "createdAt": "…",
    "lastUsedAt": null
  },
  "secret": "vk_live_<64 hex>",
  "note": "Store this secret now — it will not be shown again."
}
  • secret is returned once. Valta stores only its SHA-256.
  • The plan limit counts active keys across the account, not per agent. Over it:
json
402
{
  "error": "Your Free plan allows 1 active virtual key, and this account already has 1 (on agent wallet-guardian). Use that key, revoke it on its agent's page, or upgrade to Builder (10 active virtual keys) at https://valta.co/dashboard/subscriptions.",
  "code": "PLAN_VIRTUAL_KEY_LIMIT",
  "activeKeyAgents": ["wallet-guardian"],
  "plan": "FREE",
  "limit": "1 active virtual key",
  "upgradeTo": "Builder",
  "upgradeUrl": "https://valta.co/dashboard/subscriptions"
}

GET /api/v1/agents/:id/virtual-keys — requires read. Returns { success, virtualKeys: [...] } (metadata only, never secrets, newest first).

Revoke a virtual key

DELETE /api/v1/agents/:id/virtual-keys/:keyId — requires write. Returns { success: true }, or 404 if it doesn't exist or is already revoked. The next proxy call with that key gets 401.

Chat Completions through Valta

POST https://valta.co/v1/chat/completions

HeaderRequiredNotes
Authorization: Bearer vk_live_…YesOr x-api-key: vk_live_….
Content-Type: application/jsonYes
X-Valta-Run-IdRecommended1–200 chars of A-Z a-z 0-9 . _ : -. Calls with the same run id share the per-run limit. Without it, each call is its own run.

Body: the OpenAI Chat Completions request, unchanged. model and a non-empty messages are required. stream: true returns 400 stream_not_supported.

What Valta does, in order:

  1. Resolves the virtual key (401 if unknown or revoked).
  2. Checks the plan's active-key count (402 plan_key_limit) and the per-key rate limit (429 rate_limited, with Retry-After: 60). Every request on the key counts toward the rate limit, including denied ones.
  3. Checks an OpenAI key is stored for the agent (403 no_provider_key).
  4. Estimates the cost: prompt size at ~4 characters per token, plus max_completion_tokens / max_tokens (default 1,024 if neither is set), times n, at the model's OpenAI list price. Models Valta has no price for are estimated at the most expensive tier.
  5. Runs Cap: freeze, Cap enabled, per-run / daily / monthly limits, then the plan's Cap agent count and tracked-USD budget — the same checks and ledger as cap.allow().
  6. Approved: one request to https://api.openai.com/v1/chat/completions with the stored key, 100-second timeout, no retries by Valta.
  7. Settles the ledger to the real cost from OpenAI's usage (up or down). OpenAI 4xx → the estimate is released. Timeout or 5xx → the estimate stays charged, since OpenAI may have run it.

Approved response: OpenAI's status and body, unchanged, plus:

HeaderValue
X-Valta-Decisionapproved
X-Valta-Allow-IdThe Cap decision id (allow_…).
X-Valta-Run-IdThe run id used (yours, or a generated req_…).
X-Valta-Estimated-UsdPre-call estimate.
X-Valta-Actual-UsdReal cost from OpenAI's usage (when known).

If OpenAI returns an error after approval, it's passed through with OpenAI's status; any echoed key fragments (sk-…) are removed first.

Denied response: 402, 403, 429, or 503 with headers X-Valta-Decision: denied and X-Valta-Reason: <reason>, and:

json
{
  "approved": false,
  "reason": "plan_limit",
  "id": "allow_…",
  "message": "Your Valta Free plan's tracked spend for this month ($50) is used up. No request was sent to OpenAI. Upgrade to Builder ($500 tracked per month) at https://valta.co/dashboard/subscriptions. Tracked spend resets on the 1st of the month (UTC).",
  "plan": "FREE",
  "limit": "$50 tracked per month",
  "upgradeTo": "Builder",
  "upgradeUrl": "https://valta.co/dashboard/subscriptions",
  "error": { "message": "…", "type": "valta_denied", "code": "plan_limit" }
}

plan, limit, upgradeTo, and upgradeUrl appear only on plan denies. id is the Cap decision id, or a deny_… id for refusals before Cap runs; either one can be looked up by Valta support.

reasonHTTPCause
per_run_limit402This call would push the run (X-Valta-Run-Id) over its per-run cap.
daily_limit / monthly_limit402Over the agent's daily / monthly cap (UTC).
plan_limit402The account's tracked USD for the month would pass the plan's limit.
plan_agent_limit402A new agent, and the plan's Cap agents for the month are all in use.
plan_key_limit402This key is beyond the plan's active-key count (oldest keys win).
frozen403The agent is frozen.
cap_disabled403Cap isn't enabled on the agent.
no_provider_key403No OpenAI key stored for the agent.
rate_limited429Over the key's requests per minute. Retry-After: 60.
valta_unavailable503Valta couldn't decide. See below.

What to do about each: Error codes.

Fail closed

Valta forwards a request only after an explicit approve. Anything else — a deny, a database error, a plan lookup that fails, a stored key that can't be decrypted — returns 503 valta_unavailable (or the deny above) and nothing is sent to OpenAI. There is no bypass flag and no fail-open mode.

Run spend lives in Valta, not in your process. If the agent crashes and restarts with the same X-Valta-Run-Id, the run is still charged for everything it already spent, so the next call over the cap is still 402 per_run_limit.

The OpenAI SDKs don't auto-retry 402 or 403. They do retry 429 and 5xx by default; set max_retries=0 if you don't want that.

Health

GET https://valta.co/v1/health — no auth.

json
200
{
  "status": "ok",
  "failClosed": true,
  "decisions": "available",
  "endpoints": ["POST /v1/chat/completions"],
  "streaming": false,
  "upstream": "api.openai.com",
  "latencyMs": 72
}

503 with "status": "degraded" means Valta can't reach its database — every proxy call is being denied (503 valta_unavailable), none forwarded.

Freeze

POST /api/v1/agents/:id/freeze and POST /api/v1/agents/:id/unfreeze work for proxy agents too, including ids that exist only as a Cap policy or virtual key. A frozen agent's next proxy call gets 403 frozen. See Kill switch.

Plan limits

FreeBuilder ($29/mo)Startup ($99/mo)Enterprise
Active virtual keys (per account)11050Unlimited
Proxy requests / minute / key101206003,000
Cap agents / month11050Unlimited
Tracked USD / month (Cap + proxy, all agents)$50$500$5,000Unlimited

What's paid, and to whom:

  • Tokens are billed by OpenAI to your own OpenAI account, on the key you stored. Valta doesn't resell or mark them up, and never charges for tokens.
  • The Valta plan is what you pay Valta. Free is $0 and gets the whole proxy, with the limits above — 1 virtual key and $50 of tracked spend a month, so there's no unlimited free proxy. Builder ($29/mo) and Startup ($99/mo) raise the key count, request rate, and tracked spend. Going over the plan's tracked spend is a 402 plan_limit deny, never a silent pass.
  • Tracked USD is Valta's estimate settled to OpenAI's reported cost, summed across all your agents, for Cap allow() and the proxy combined. It resets on the 1st (UTC).