Getting started

Workspace OpenAPI is for server-side automation. Each OpenAPI Key belongs to one workspace and can perform only its assigned operations. A request cannot switch workspaces through workspace_id.

Use its dedicated endpoint and Bearer credential. A model API key (sk-apigo-...) cannot authenticate here; an OpenAPI Key cannot run inference, sign in to the console, or manage other OpenAPI Keys. For model access, see API keys.

Create and retrieve a key

  1. Select your workspace in the console and open Governance & Audit → OpenAPI Keys.
  2. As a workspace owner or admin, create a key, set its name and expiration, and select the required permissions. Start with workspace:read and usage:read for read-only access.
  3. In an enterprise workspace, select the members allowed to view the secret. The creator is authorized automatically. Personal workspaces do not show member authorization or member management permissions.
  4. An authorized active member can reveal and copy the secret. Store it in your server-side secret manager.

Operation permissions control what the machine can do. Secret access controls who can retrieve the credential. Management access does not automatically grant secret access. Removing a viewer does not invalidate a token they already copied. Rotate, disable, or revoke the key to cut off that access, and update your services after rotation.

Endpoint and authentication

Obtain the dedicated Workspace OpenAPI root URL from your deployment administrator. Set OPENAPI_BASE_URL without a trailing /v1. Do not use the model gateway Base URL. Use the deployment's HTTPS domain in production.

The current deployment uses a dedicated listener on 18891. PLATFORM_SERVER_OPENAPI_HTTP_ADDR can change this address; an empty address disables the listener. An external gateway uses its own HTTP/HTTPS port, so you do not append :18891 to its domain.

The configured local Kubernetes endpoint is:

export OPENAPI_BASE_URL='http://openapi.localhost'
# Inject OPENAPI_KEY from your secret manager; keep it out of source and browser code.
curl --fail-with-body "$OPENAPI_BASE_URL/v1/workspace" \
  -H "Authorization: Bearer $OPENAPI_KEY"

To connect directly to the local Kubernetes Service, run this command and use http://127.0.0.1:18891 in another terminal. The Service port is not automatically exposed on your host.

kubectl --context orbstack -n tidemind port-forward svc/platform-openapi 18891:18891

The dedicated service serves the full request, response, and x-scope definitions at GET /openapi.json. Import this document into an OpenAPI-compatible client:

curl --fail-with-body "$OPENAPI_BASE_URL/openapi.json" -o workspace-openapi.json

Operations and permissions

Use the exact permission names below; wildcards are unsupported. Paths are relative to the dedicated root URL. Replace {id} with an external ID returned by the API.

Method and path Permission Purpose
GET /v1/workspace workspace:read Read the current workspace
GET /v1/api-keys api_keys:read List model API key metadata without secrets
POST /v1/api-keys api_keys:create Create a model API key for an active member
PATCH /v1/api-keys/{id} api_keys:update Update model API key limits
POST /v1/api-keys/{id}/disable api_keys:disable Disable a model API key
DELETE /v1/api-keys/{id} api_keys:delete Delete a model API key
GET /v1/usage usage:read Query workspace usage
GET /v1/bills billing:read Query bills and funding records
GET /v1/members members:read List enterprise workspace members
POST /v1/members/invitations members:invite Invite an ordinary member
DELETE /v1/members/{id} members:remove Remove an ordinary member

Invitations accept email and optional name, with no role elevation. Removal cannot target an owner, admin, or manager. An invitation response with email_queued indicates queued email, not confirmed delivery.

Query usage and bills

Usage requires range: 1h, 1d, 7d, 30d, month, or custom. A custom range requires both from and to and cannot exceed 30 days.

curl --fail-with-body "$OPENAPI_BASE_URL/v1/usage?range=7d" \
  -H "Authorization: Bearer $OPENAPI_KEY"

curl --fail-with-body "$OPENAPI_BASE_URL/v1/bills?page=1&page_size=20" \
  -H "Authorization: Bearer $OPENAPI_KEY"

Bills also support type, from, and to filters. Times accept RFC3339 or YYYY-MM-DD dates interpreted in UTC. An RFC3339 to is exclusive; a date-only to includes that day.

Key, bill, and member lists accept page and page_size, defaulting to page 1 and 20 items, with a maximum of 100 items. Their data contains items, total, page, and page_size. Usage does not use this pagination envelope.

Writes and retries

Every write requires an Idempotency-Key of 1–200 bytes. Generate a unique request ID for each new business operation. Keep the same ID and payload for network retries. For the same machine key, operation, and request ID, identical parameters reuse the original result; changed parameters return 409. Do not generate a fresh request ID on every retry.

This example updates an existing model API key's RPM. Set MODEL_KEY_ID to its real ID from the list and REQUEST_ID to this operation's unique request ID:

curl --fail-with-body -X PATCH "$OPENAPI_BASE_URL/v1/api-keys/$MODEL_KEY_ID" \
  -H "Authorization: Bearer $OPENAPI_KEY" \
  -H "Idempotency-Key: $REQUEST_ID" \
  -H 'Content-Type: application/json' \
  --data '{"limits":{"rpm_limit":60}}'

Updates accept only limits. Omitted limits remain unchanged. Dollar limits day_limit_usd, d7_limit_usd, and d30_limit_usd accept up to two decimal places; explicit null clears a limit. Daily ≤ 7-day ≤ 30-day limits must hold. Values of 0 or null for rpm_limit, tpm_limit, and concurrency_limit remain subject to workspace hard limits. See Limits and enforcement.

To create a model API key, provide name, an active workspace member's member_id, billing_type: "credit_balance", and optional limits. Enterprise workspaces can retrieve member IDs through the members endpoint. The response includes data.key and the new key's data.full_secret. An idempotent replay can recover this creation result; ordinary lists and updates never return secrets.

Responses and errors

JSON responses use { "code": 0, "message": "ok", "data": ... }, where code: 0 indicates success. Check both the HTTP status and business code, not just whether the response is JSON.

HTTP status What to check
400 Invalid parameters, time range, limits, or idempotency request ID
401 Missing, incorrect, expired, disabled, or revoked Bearer key
403 The key lacks the operation's required permission
404 The resource is missing or belongs to another workspace
409 An idempotency ID was reused with different parameters, or resource state conflicts
429 Too many requests; reduce concurrency and retry with backoff

Never log Authorization or secret values. Keep sanitized HTTP statuses, business error codes, and operation paths for troubleshooting. Preserve the original idempotency request ID when retrying writes.