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
- Select your workspace in the console and open Governance & Audit → OpenAPI Keys.
- As a workspace owner or admin, create a key, set its name and expiration, and select the required permissions. Start with
workspace:readandusage:readfor read-only access. - 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.
- 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.
