Skip to content

Self-service API reference (`/gw`)

Management and analytics API for your organization. All endpoints:

  • Base URL: https://api.sociaro.com/gw
  • Auth: Authorization: Bearer gw_live_…
  • Tenant-scoped: your organization is derived from the key — it cannot be passed (or spoofed) via parameters.
  • Errors use the standard envelope.
EndpointScope
GET /gw/meany valid key
GET /gw/ceilingkeys:manage
GET /gw/keyskeys:manage
POST /gw/keyskeys:manage
DELETE /gw/keys/{id}keys:manage
GET /gw/statsstats:read
GET /gw/usagestats:read
GET /gw/asyncstats:read

Introspect the current key: its scopes and model entitlements.

{
"scopes": ["inference:use", "stats:read"],
"entitlements": [
{"provider": "openai", "model_pattern": "gpt-4o*", "effect": "allow"}
]
}

Your organization’s ceiling: the maximum scopes and entitlement patterns that child keys may be issued with.

{
"max_scopes": ["inference:use", "stats:read", "keys:manage"],
"entitlements": [
{"provider": "openai", "model_pattern": "gpt-*", "effect": "allow"},
{"provider": "anthropic", "model_pattern": "claude-*", "effect": "allow"}
]
}

List your organization’s keys (no hashes, no plaintext).

[
{
"id": "<uuid>",
"key_prefix": "gw_live_abc12345",
"status": "active",
"scopes": ["inference:use"],
"created_at": "2026-05-28T00:00:00Z",
"last_used_at": "2026-06-09T18:12:44Z"
}
]

Issue a child key. The plaintext is returned exactly once.

Request:

{
"scopes": ["inference:use", "stats:read"],
"entitlements": [
{"provider": "openai", "model_pattern": "gpt-4o*", "effect": "allow"}
]
}

Validation is atomic: scopes must be a subset of max_scopes, and every entitlement tuple must be present in the ceiling. On violation → 403, no key created.

Response:

{"api_key_id": "<uuid>", "key": "gw_live_<48 hex>", "scopes": ["inference:use", "stats:read"]}

Keys are immutable — to change permissions, revoke and re-issue. Ceiling changes are not retroactive: already-issued keys keep their permissions.

Revoke a key (soft delete — usage history is preserved). 204 No Content on success, 404 if the key does not belong to your organization.

Aggregated requests / tokens / cost, grouped by a dimension.

ParamDefaultValues
group_byproviderprovider, model, day, or any attribution key (project, team, …)
since30d30d, 7d, 24h, 90md suffix for days, otherwise Go duration
providerfilter by provider

Response (sorted by total_cost_usd desc; group_by=day is chronological):

[
{"key": "openai", "requests": 1240, "total_tokens": 815000, "total_cost_usd": 42.17},
{"key": "anthropic", "requests": 311, "total_tokens": 99000, "total_cost_usd": 8.05}
]

An empty "key": "" bucket collects records missing the requested attribution key.

Raw usage rows, newest first.

ParamDefaultValues
providerfilter by provider
parse_statusok, partial, unknown; async also provisional, failed, cancelled, expired
since30d, 24h, …
limit1001..1000 (out of range → 400)
[
{
"id": "<uuid>",
"client_id": "<uuid>",
"provider": "openai",
"model": "gpt-4o",
"cost_usd": 0.00075,
"total_tokens": 150,
"status_code": 200,
"latency_ms": 840,
"parse_status": "ok",
"attribution": {"project": "alpha"},
"created_at": "2026-05-28T00:00:00Z"
}
]

Your async job ledger — see async jobs for semantics.

ParamDefaultValues
scopekeykey (this key’s jobs) or client (whole organization)
statuspending, succeeded, failed, cancelled, expired
kindvideo, image, 3d
created_after / created_beforeRFC3339
limit1001..500 (clamped)
cursoropaque cursor from next_cursor
{
"data": [
{
"task_id": "cgt-2026...",
"provider": "byteplus",
"model": "ep-m-...",
"kind": "video",
"status": "succeeded",
"provisional_cost_usd": 1.25,
"final_cost_usd": 1.10,
"expiration_reason": null,
"attribution": {"project": "alpha"},
"created_at": "2026-06-10T12:00:00Z",
"finalized_at": "2026-06-10T12:04:31Z"
}
],
"next_cursor": ""
}