API key management

⚠️
Preview — this feature is being built; the design below is the spec.

These endpoints let an admin key see every inference key in the organization, rename keys, change their network restrictions, and switch them off and on. Use them for scheduled key hygiene (disable keys that have not been used in 90 days), for incident response (switch off every key a departing employee created), and for inventory reports.

Creating keys stays in the Console. A new secret should be shown to one person, once, not passed through scripts. See Managing API keys.

Endpoints

MethodPathPurpose
GET/v1/organizations/api_keysList inference keys.
GET/v1/organizations/api_keys/{api_key_id}Read one key.
PATCH/v1/organizations/api_keys/{api_key_id}Change name, status or restrictions.

Authenticate with an admin key and send syntic-beta: admin-2026-11-01. Keys created by Owners and Administrators see and change every key.

The API key object

{
  "id": "apikey_01JB7C9E1G3J5L7N9Q1S",
  "type": "api_key",
  "name": "billing-worker-prod",
  "kind": "private",
  "prefix": "sk_live_3f9c",
  "hint": "…a71e",
  "status": "active",
  "workspace_id": "wrkspc_01JC0A2C4E6G8J0L2N4Q",
  "created_by": { "id": "user_01J9Y0A2C4E6G8J0L2N4", "email": "dana@example.com", "status": "active" },
  "allowed_origins": [],
  "allowed_ips": ["203.0.113.0/24"],
  "pinned_version": "2026-11-01",
  "expires_at": null,
  "created_at": "2026-03-02T09:30:00Z",
  "last_used_at": "2026-11-05T10:02:11Z",
  "last_used_ip": "203.0.113.40",
  "use_count": 1841220
}
FieldDescription
kindprivate (sk_live_), public (pk_live_) or syntic_code (sk_syntic_).
prefix, hintThe first and last few characters, enough to match a key against a leaked or logged value. The secret itself is never returned.
statusactive, inactive (switched off, can be switched back on), revoked (permanent) or expired.
created_by.statusIf the creator is not active, the key does not work even when its own status is active.
allowed_origins, allowed_ipsNetwork restrictions. See Allowed origins and IP allowlists.
pinned_versionThe syntic-version the key uses by default. See Versioning.
last_used_at, last_used_ip, use_countUsage, updated at most once a minute.

List keys

GET /v1/organizations/api_keys

Query parameterNotes
statusactive (default), inactive, revoked, expired or all.
workspace_idKeys in one workspace.
created_byKeys created by one member.
unused_sinceRFC 3339 time: keys whose last_used_at is earlier, or never used.
limit, after_id, before_idCursor pagination.

Update a key

PATCH /v1/organizations/api_keys/{api_key_id}

FieldNotes
name1 to 100 characters.
statusactive or inactive. Revoking (permanent) stays in the Console.
allowed_originsReplaces the list.
allowed_ipsReplaces the list.
pinned_versionMove the key’s default API version.

A key switched to inactive fails with 401 authentication, code inactive_api_key, from the next request.

Example: disable keys unused for 90 days

CUTOFF=$(date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%SZ)
curl -sS -G https://app.syntic.ai/v1/organizations/api_keys \
  -H "Authorization: Bearer $SYNTIC_ADMIN_KEY" \
  -H "syntic-beta: admin-2026-11-01" \
  --data-urlencode "unused_since=$CUTOFF" --data-urlencode "limit=100" \
| jq -r '.data[].id' | while read -r ID; do
  curl -sS -X PATCH "https://app.syntic.ai/v1/organizations/api_keys/$ID" \
    -H "Authorization: Bearer $SYNTIC_ADMIN_KEY" \
    -H "Content-Type: application/json" \
    -H "syntic-beta: admin-2026-11-01" \
    -d '{"status": "inactive"}' > /dev/null && echo "disabled $ID"
done

Errors

Errors use the error envelope.

StatustypecodeWhen
400invalid_request_errorinvalid_parameterA bad origin, IP range or version; param names it.
400invalid_request_errorread_only_fieldTrying to set kind, workspace_id or the secret.
404not_found_errorapi_key_not_foundNo such key in the organization.
409conflict_errorkey_revokedChanging a revoked or expired key.

Build notes for the platform team

  • Wrap the existing key functions; add the inactive status (reversible) alongside revoked (permanent).
  • Return prefix and hint only. The secret hash never leaves the database layer.
  • Every PATCH writes api_key.updated with the changed fields.
Was this page helpful?