The descriptions of the operations and fields are the contract’s own, in English.
/metering/v1/usageRead a usage fact back by idempotency key
- Credential
- API key
- Permission
usage.read
Reads back the ingested C2 usage record by its canonical idempotency key (the idempotency_key query parameter, in the key's canonical compact-JSON form, percent-encoded). The response is the codec's exact C2 wire bytes — byte-identical to the ingested fixture. A key that was never applied is 404 usage-not-found.
curl "https://console.eu.ccsio.ai/metering/v1/usage?idempotency_key=<idempotency_key>" \
-H "Authorization: Bearer $CCSIO_API_KEY"Parameters
| Name | In | Description |
|---|---|---|
X-Request-IDoptional | header | string Optional request ULID. A valid ULID (upper or lowercase) is honored; when the header is absent or invalid, the runtime mints the id. The response X-Request-ID header carries the canonical uppercase form. |
idempotency_keyrequired | query | string The key's canonical C2 form: compact JSON, five fields in schema order (tenant_id, plane_instance_id, request_or_run_id, attempt, provider_response_id), percent-encoded; the object shape is the C2 schema's idempotency_key; out-of-form is idempotency-key-invalid, distinct from invalid-request. |
Responses
- 200
The usage fact, in its C2 wire form.
Schema
UsageRecorddeployment_idstring or nulloptionalpattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
provider_classanyoptionalAllowed values:
"CCSIO_INFERENCE""CUSTOMER_HOSTED""EXTERNAL_MANAGED"nullrequest_duration_msinteger or nulloptionalWhole router request timing, shared by all attempt records; absent on legacy records.
0 to 9007199254740991
request_ttft_msinteger or nulloptionalWhole router request timing, shared by all attempt records; absent on legacy records.
0 to 9007199254740991
session_idstring or nulloptionalClient-provided session label (the X-Session-Id request header), copied onto every attempt record of the request; absent or null when the client sent none. It groups requests for the operator; it is never an identity and never used for authorization or tenancy.
pattern ^[A-Za-z0-9._:-]{1,128}$
http_statusinteger or nulloptionalThe HTTP status the router answered for the whole request: its single response, identical on every attempt record of the request (the per-attempt result is outcome_class). A request that failed after the response header was committed (a stream cut mid-way) keeps the committed status, 200. Absent or null on legacy records.
100 to 599
error_codestring or nulloptionalThe stable error code of the router's response to the request (the OpenAI-format error.code, or the platform error code on the routes that answer in that envelope), identical on every attempt record of the request; for a stream cut after the header was committed it is the code of the terminal error frame, or, on the surfaces that write no terminal frame (a cut chat stream, an aborted audio transfer), the code the failure classifies to. Null or absent when the request succeeded and on legacy records.
pattern ^[a-z][a-z0-9._-]{0,127}$
api_key_idstring or nulloptionalThe id of the API key the request was authenticated with (the key's key_id in the identity API, never the key itself), copied by the router from the signed context onto every attempt record of the request; absent or null for a request made without an API key, such as one from a console session. It says which credential was used; it is never an identity and never used for authorization or tenancy.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
schema_versionanyrequiredalways "c2/v1"
event_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
idempotency_keyobjectrequiredtenant_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
plane_instance_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
request_or_run_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
attemptintegerrequired1 to 9007199254740991
provider_response_idone of or nullrequiredOne of
#1stringoptionalpattern ^[a-z][a-z0-9._-]{0,127}$
#2anyoptionalalways ""
occurred_atstring (utc-second)requiredpattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
emitted_atstring (utc-second)requiredpattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
monotonic_since_boot_msintegerrequired0 to 9007199254740991
seqobjectrequiredstream_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
nintegerrequired1 to 9007199254740991
meter_epochstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
tenant_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
team_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
principal_classstringrequiredAllowed values:
"user""service""agent"principal_refstringrequiredOriginal authenticated principal reference, preserved byte-for-byte under the C0 identity grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
planestringrequiredAllowed values:
"ai""agent""memory""brain"operationstringrequiredAllowed values:
"chat""embedding""audio""image""document""tool""agent_overhead""responses""decision"accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"model_aliasstringrequiredOriginal selected model reference, preserved byte-for-byte under the C0 model registry grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
model_catalog_entry_digeststringrequiredpattern ^[a-f0-9]{64}$
request_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
run_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
agent_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
agent_spec_digeststring or nullrequiredpattern ^[a-f0-9]{64}$
quantitiesarray of objectrequiredat most 16 items
unitstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
amountstringrequiredpattern ^(0|[1-9][0-9]{0,17})(\.[0-9]{0,8}[1-9])?$
measurementstringrequiredAllowed values:
"measured""estimated""unknown"measurement_reasonstring or nullrequiredAllowed values:
"coarse_counter""provider_estimate""final_usage_missing""meter_loss""canceled""implausible_count"duration_msinteger or nullrequired0 to 9007199254740991
ttft_msinteger or nullrequired0 to 9007199254740991
request_countintegerrequired0 to 9007199254740991
tool_call_countintegerrequired0 to 9007199254740991
outcome_classstringrequiredAllowed values:
"success""error""canceled""unknown"data_classificationstringrequiredAllowed values:
"public""internal""restricted"routing_inputsobjectrequiredrule_idsarray of stringrequiredat most 16 items
classification_labelstringrequiredAllowed values:
"public""internal""restricted"priority_groupstringrequiredAllowed values:
"low""normal""high"
routing_inputs_digeststringrequiredpattern ^[a-f0-9]{64}$
bundle_versionintegerrequired1 to 9007199254740991
bundle_digeststringrequiredpattern ^[a-f0-9]{64}$
- 400
Client refusal unrelated to authentication, including malformed input, a denied or failed request.
- 401
The request carries no credential, more than one, or one the platform does not accept, and is refused before the operation runs; `error.code` says why. Supply exactly one credential. Codes: invalid-request (no credential, or both Authorization:
Read more
Bearer and x-api-key), api-key-invalid (a value that is not a platform API key, or a key of a kind the platform does not accept), api-key-unknown, api-key-revoked, api-key-expired, bootstrap-disabled (the one-shot installation credential, once a key exists), token-malformed (a bearer token that is not a JWT), token-algorithm-unsupported, token-signature-invalid, token-claim-invalid, token-issuer-mismatch, token-audience-mismatch, token-expired, token-not-yet-valid, issuer-untrusted, issuer-residency-mismatch (the issuer belongs to another plane), issuer-resolution-unknown, jwks-unavailable, jwks-key-not-found, staff-token-inactive (a platform operator's token), staff-not-operator, staff-directory-unavailable, identity-not-provisioned (a verified identity with no account on this plane), organization-not-found (a verified identity or key whose organization this plane does not know), internal-error (a fault while the credential is checked is refused too, fail closed), context-cancelled
- 402
The organization has to pay first: its standing is payment_required.
Read more
The request boundary applies this payment gate to every route except an organization's billing routes, the caller's own context, organization list, onboarding, session report and personal keys, the public routes, and the routes of platform operators, who administer an organization that has to pay. The operations the gate covers declare this response. On /v1 the refusal is rendered in the OpenAI error format. Code: payment-required
- 403
The credential is valid but may not do this here; the request is refused by the request boundary before the handler runs, and `error.code` says which refusal. An operation may add codes of its own.
Read more
Codes: policy-denied (no role of the caller holds the permission the operation needs, or the credential class may not call it: a personal API key outside inference and MCP, a route that needs a signed-in person, the one-shot installation credential outside its three steps), tenant-mismatch (the organization a path, query, body or X-Tenant header names is not the caller's own), organization-provisioning, organization-suspended, organization-disabled, organization-deleted (the state of the caller's organization), user-disabled, residency-mismatch (the organization lives on another plane), organization-selection-required (a caller with more than one organization, or a platform operator, must name one in X-Organization-Id), organization-not-selectable, no-active-organization-membership, team-not-selectable (the X-Organization-Id or X-Team-Id the caller sent does not name an organization or team it may act in), identity-managed-by-provider (a person who is not a platform operator changes an organization's status, which belongs to the identity provider), support-session-required (a platform operator reads an organization's data without an open support session)
- 404
The requested resource or path was not found.
- 405
The path is claimed but the request method is not allowed. Go ServeMux returns its standard plain-text response and lists permitted methods in Allow.
- 500
Platform failure, rendered without internal cause details.
/metering/v1/usageIngest one C2 usage record
- Credential
- API key
- Permission
usage.manage- Request body
- Body up to 1 MiB
Ingests one C2 v1 usage record. The body is the strict C2 profile (unknown fields and trailing data rejected). Idempotent under redelivery: a duplicate key renders exactly {"status":"redelivered"} with no event_id or checkpoint.
Read more
First delivery renders {"status":"ingested","event_id":...,"checkpoint":{...}}; event_id is present only when usage-event emission is enabled on the serving role (see info). The request body is capped at 1048576 bytes; over-cap is 400 invalid-request, never 413.
curl -X POST "https://console.eu.ccsio.ai/metering/v1/usage" \
-H "Authorization: Bearer $CCSIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": null,
"event_id": "string",
"idempotency_key": {
"tenant_id": "string",
"plane_instance_id": "string",
"request_or_run_id": "string",
"attempt": 0,
"provider_response_id": "string"
},
"occurred_at": "string",
"emitted_at": "string",
"monotonic_since_boot_ms": 0,
"seq": {
"stream_id": "string",
"n": 0
},
"meter_epoch": "string",
"tenant_id": "string",
"team_id": "string",
"principal_class": "user",
"principal_ref": "string",
"plane": "ai",
"operation": "chat",
"accounting_scope": "provider_attempt",
"model_alias": "string",
"model_catalog_entry_digest": "string",
"request_id": "string",
"run_id": "string",
"agent_id": "string",
"agent_spec_digest": "string",
"quantities": [
{
"unit": "string",
"amount": "string"
}
],
"measurement": "measured",
"measurement_reason": "coarse_counter",
"duration_ms": 0,
"ttft_ms": 0,
"request_count": 0,
"tool_call_count": 0,
"outcome_class": "success",
"data_classification": "public",
"routing_inputs": {
"rule_ids": [
"string"
],
"classification_label": "public",
"priority_group": "low"
},
"routing_inputs_digest": "string",
"bundle_version": 0,
"bundle_digest": "string"
}'Parameters
| Name | In | Description |
|---|---|---|
X-Request-IDoptional | header | string Optional request ULID. A valid ULID (upper or lowercase) is honored; when the header is absent or invalid, the runtime mints the id. The response X-Request-ID header carries the canonical uppercase form. |
Request body application/json
deployment_idstring or nulloptionalpattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
provider_classanyoptionalAllowed values:
"CCSIO_INFERENCE""CUSTOMER_HOSTED""EXTERNAL_MANAGED"nullrequest_duration_msinteger or nulloptionalWhole router request timing, shared by all attempt records; absent on legacy records.
0 to 9007199254740991
request_ttft_msinteger or nulloptionalWhole router request timing, shared by all attempt records; absent on legacy records.
0 to 9007199254740991
session_idstring or nulloptionalClient-provided session label (the X-Session-Id request header), copied onto every attempt record of the request; absent or null when the client sent none. It groups requests for the operator; it is never an identity and never used for authorization or tenancy.
pattern ^[A-Za-z0-9._:-]{1,128}$
http_statusinteger or nulloptionalThe HTTP status the router answered for the whole request: its single response, identical on every attempt record of the request (the per-attempt result is outcome_class). A request that failed after the response header was committed (a stream cut mid-way) keeps the committed status, 200. Absent or null on legacy records.
100 to 599
error_codestring or nulloptionalThe stable error code of the router's response to the request (the OpenAI-format error.code, or the platform error code on the routes that answer in that envelope), identical on every attempt record of the request; for a stream cut after the header was committed it is the code of the terminal error frame, or, on the surfaces that write no terminal frame (a cut chat stream, an aborted audio transfer), the code the failure classifies to. Null or absent when the request succeeded and on legacy records.
pattern ^[a-z][a-z0-9._-]{0,127}$
api_key_idstring or nulloptionalThe id of the API key the request was authenticated with (the key's key_id in the identity API, never the key itself), copied by the router from the signed context onto every attempt record of the request; absent or null for a request made without an API key, such as one from a console session. It says which credential was used; it is never an identity and never used for authorization or tenancy.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
schema_versionanyrequiredalways "c2/v1"
event_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
idempotency_keyobjectrequiredtenant_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
plane_instance_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
request_or_run_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
attemptintegerrequired1 to 9007199254740991
provider_response_idone of or nullrequiredOne of
#1stringoptionalpattern ^[a-z][a-z0-9._-]{0,127}$
#2anyoptionalalways ""
occurred_atstring (utc-second)requiredpattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
emitted_atstring (utc-second)requiredpattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
monotonic_since_boot_msintegerrequired0 to 9007199254740991
seqobjectrequiredstream_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
nintegerrequired1 to 9007199254740991
meter_epochstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
tenant_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
team_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
principal_classstringrequiredAllowed values:
"user""service""agent"principal_refstringrequiredOriginal authenticated principal reference, preserved byte-for-byte under the C0 identity grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
planestringrequiredAllowed values:
"ai""agent""memory""brain"operationstringrequiredAllowed values:
"chat""embedding""audio""image""document""tool""agent_overhead""responses""decision"accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"model_aliasstringrequiredOriginal selected model reference, preserved byte-for-byte under the C0 model registry grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
model_catalog_entry_digeststringrequiredpattern ^[a-f0-9]{64}$
request_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
run_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
agent_idstring or nullrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
agent_spec_digeststring or nullrequiredpattern ^[a-f0-9]{64}$
quantitiesarray of objectrequiredat most 16 items
unitstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
amountstringrequiredpattern ^(0|[1-9][0-9]{0,17})(\.[0-9]{0,8}[1-9])?$
measurementstringrequiredAllowed values:
"measured""estimated""unknown"measurement_reasonstring or nullrequiredAllowed values:
"coarse_counter""provider_estimate""final_usage_missing""meter_loss""canceled""implausible_count"duration_msinteger or nullrequired0 to 9007199254740991
ttft_msinteger or nullrequired0 to 9007199254740991
request_countintegerrequired0 to 9007199254740991
tool_call_countintegerrequired0 to 9007199254740991
outcome_classstringrequiredAllowed values:
"success""error""canceled""unknown"data_classificationstringrequiredAllowed values:
"public""internal""restricted"routing_inputsobjectrequiredrule_idsarray of stringrequiredat most 16 items
classification_labelstringrequiredAllowed values:
"public""internal""restricted"priority_groupstringrequiredAllowed values:
"low""normal""high"
routing_inputs_digeststringrequiredpattern ^[a-f0-9]{64}$
bundle_versionintegerrequired1 to 9007199254740991
bundle_digeststringrequiredpattern ^[a-f0-9]{64}$
Responses
- 200
The usage record was ingested (or redelivered).
Schema
IngestResponsestatusstringrequiredThe ingest result: ingested (first delivery) or redelivered (duplicate key).
Allowed values:
"ingested""redelivered"event_idstringoptionalThe durable outbox row's ULID, minted at enqueue (first delivery only; omitted on redelivery; present only when usage-event emission is enabled on the serving role).
pattern ^[0-9A-HJKMNP-TV-Z]{26}$
checkpointobjectoptionalThe scope's C3 checkpoint cursors (first delivery only; omitted on redelivery).
tenant_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
plane_instance_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
stream_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
contiguous_usage_throughintegerrequired0 to 9007199254740991
usage_high_waterintegerrequired0 to 9007199254740991
- 400
Client refusal unrelated to authentication, including malformed input, a denied or failed request.
- 401
The request carries no credential, more than one, or one the platform does not accept, and is refused before the operation runs; `error.code` says why. Supply exactly one credential. Codes: invalid-request (no credential, or both Authorization:
Read more
Bearer and x-api-key), api-key-invalid (a value that is not a platform API key, or a key of a kind the platform does not accept), api-key-unknown, api-key-revoked, api-key-expired, bootstrap-disabled (the one-shot installation credential, once a key exists), token-malformed (a bearer token that is not a JWT), token-algorithm-unsupported, token-signature-invalid, token-claim-invalid, token-issuer-mismatch, token-audience-mismatch, token-expired, token-not-yet-valid, issuer-untrusted, issuer-residency-mismatch (the issuer belongs to another plane), issuer-resolution-unknown, jwks-unavailable, jwks-key-not-found, staff-token-inactive (a platform operator's token), staff-not-operator, staff-directory-unavailable, identity-not-provisioned (a verified identity with no account on this plane), organization-not-found (a verified identity or key whose organization this plane does not know), internal-error (a fault while the credential is checked is refused too, fail closed), context-cancelled
- 402
The organization has to pay first: its standing is payment_required.
Read more
The request boundary applies this payment gate to every route except an organization's billing routes, the caller's own context, organization list, onboarding, session report and personal keys, the public routes, and the routes of platform operators, who administer an organization that has to pay. The operations the gate covers declare this response. On /v1 the refusal is rendered in the OpenAI error format. Code: payment-required
- 403
The credential is valid but may not do this here; the request is refused by the request boundary before the handler runs, and `error.code` says which refusal. An operation may add codes of its own.
Read more
Codes: policy-denied (no role of the caller holds the permission the operation needs, or the credential class may not call it: a personal API key outside inference and MCP, a route that needs a signed-in person, the one-shot installation credential outside its three steps), tenant-mismatch (the organization a path, query, body or X-Tenant header names is not the caller's own), organization-provisioning, organization-suspended, organization-disabled, organization-deleted (the state of the caller's organization), user-disabled, residency-mismatch (the organization lives on another plane), organization-selection-required (a caller with more than one organization, or a platform operator, must name one in X-Organization-Id), organization-not-selectable, no-active-organization-membership, team-not-selectable (the X-Organization-Id or X-Team-Id the caller sent does not name an organization or team it may act in), identity-managed-by-provider (a person who is not a platform operator changes an organization's status, which belongs to the identity provider), support-session-required (a platform operator reads an organization's data without an open support session)
- 405
The path is claimed but the request method is not allowed. Go ServeMux returns its standard plain-text response and lists permitted methods in Allow.
- 500
Platform failure, rendered without internal cause details.
/metering/v1/usage/summarySummarize the selected organization's usage
- Credential
- API key
- Permission
- Any of
usage.read_ownusage.readplatform-usage.readsupport-access.read
The organization is derived exclusively from the verified actor context; tenant or organization query parameters are not accepted. Reads occurred_at in the half-open [from, to) UTC interval, defaulting to the last 7 days and capped at 90 days. Counts and quantities are exact strings.
Read more
Metrics retain accounting_scope so provider attempts, platform overhead, and agent aggregates are not double-counted as a single total. Unknown or duplicate query parameters and invalid windows return 400; a missing selected organization returns 403. Windows with no usage return empty scopes/models/by_principal, zero daily series, and cost unavailable. Optional model_alias and accounting_scope filters apply to the full requested window before aggregation or pagination; filtering never operates on a truncated request page. The optional principal filter (a principal_ref or an email address, with the request-log principal filter's validation, case-insensitive email resolution and visibility rule) narrows every total, daily bucket and breakdown to that principal's usage. The optional api_key_id filter narrows them to the usage made with one API key; with both, a fact must match both. by_principal breaks the filtered window down per principal: one entry per accounting scope and principal_ref, named with the email and display name resolved when the summary is read, at most 100 per accounting scope (by_principal_truncated tells when any scope was cut); the scope totals always cover every principal. Requires usage.read_own (at any level), usage.read or, for a platform operator, platform-usage.read. WHICH usage: a caller holding usage.read at organization level (the Administrator role) reads every principal's usage; a caller holding usage.read_own without it - the built-in User role, and a Team Admin, whose usage.read applies to its team's request log and not to this report - reads ONLY the usage whose principal is themselves (a member's own user principal and personal API keys, a service account the usage it made), whatever the request carries: the principal filter is forced to the caller's own reference, so a principal filter naming anyone else, by reference or by email, matches nothing (200 with an empty result, never an error and never a hint of whose usage it is - the request log's narrowing) and by_principal holds only the caller. WITH AN API KEY: these routes answer a service-account API key sent in x-api-key or as Authorization: Bearer, on the console host of the key's own organization and region; a personal API key reaches inference and MCP only and is refused here with 403 policy-denied. A key whose role holds usage.read_own without usage.read reads ONLY the usage made with that key: the facts whose api_key_id is the key's own key_id, not everything its service account made. Whatever the request carries, the read stays bound to that key and to its service account: an api_key_id naming another key (of the same service account or of anyone else) and a principal naming anyone else match nothing (200 with an empty result, never an error), and the key's own id or reference is the same read as no filter. A key whose role holds usage.read at organization level reads the organization's usage exactly as the Administrator role does and may narrow it to one key with api_key_id. Neither level reads another organization: the organization is the key's own and no parameter or header names it. A revoked or expired key is 401 api-key-revoked or api-key-expired, as on every route; an organization with no active subscription is refused with 402 payment-required before any role is checked. A caller holding none of these permissions is 403 policy-denied. A platform operator (platform-usage.read: a permission of the fixed operator set, held by no organization or team role and by no custom role) who selected the organization with the X-Organization-Id header reads the organization's totals, daily series and per-model rows exactly as the Administrator role does, with by_principal an empty list and by_principal_truncated false and nobody named: the view is not per user, so a principal or api_key_id filter is refused with 400 invalid-request, while the period, model_alias, accounting_scope and operation_class filters apply. Without a selected organization the operator is told to select one (403 organization-selection-required). The permission opens no other read: the usage page, the request logs, the usage lookup and the status reads need usage.read or usage.read_own and answer a platform operator with 403 policy-denied. The answer for the organization's own members is unchanged.
curl "https://console.eu.ccsio.ai/metering/v1/usage/summary" \
-H "Authorization: Bearer $CCSIO_API_KEY"Parameters
| Name | In | Description |
|---|---|---|
X-Request-IDoptional | header | string Optional request ULID. A valid ULID (upper or lowercase) is honored; when the header is absent or invalid, the runtime mints the id. The response X-Request-ID header carries the canonical uppercase form. |
fromoptional | query | string Inclusive UTC RFC 3339 start (must end in Z; fractional seconds allowed). Supply both from and to or omit both for the last 7 days, or the cursor's frozen window when paging. The interval must be positive and at most 90 days. |
tooptional | query | string Exclusive UTC RFC 3339 end (must end in Z; fractional seconds allowed). Required when from is supplied. |
model_aliasoptional | query | string Optional exact model reference, preserving case and punctuation. Omit for all models; a valid reference with no matching usage returns empty totals and zero daily buckets. |
accounting_scopeoptional | query | string Optional accounting scope. Omit for all scopes, which remain separate in every aggregate; the literal all is not accepted. |
principaloptional | query | one of Optional. Read moreNarrows every total, daily bucket and breakdown of the response to the usage made by this principal: the principal_ref (a C0 reference) or an email address (it contains '@'), matched case-insensitively against the organization's users and resolved to their refs, exactly as the request-log principal filter does. A reference matches the usage of that principal_ref whatever its principal_class (a member's own sessions and personal API keys share their reference). An email filter follows the visibility rule of the emails themselves: a caller who may not read the organization's member list (members.read at organization level, or a platform administrator) may filter only by their own email, any other address matches no usage; an address that matches no user matches no usage (a 200 with empty scopes, models and by_principal, zero daily buckets or an empty page — not an error — so the filter cannot be used to probe whose address it is). A value that is neither a reference nor a plain email address (no display name, no whitespace, at most 254 bytes) renders 400 invalid-request. On the page read the cursor is bound to the filter as it was typed. The platform operator's summary (platform-usage.read) is not per user: there this filter renders 400 invalid-request. For an API key reading only its own usage, a principal other than its service account's matches no usage. |
api_key_idoptional | query | string Optional. Narrows every total, daily bucket and breakdown of the response (or every record of the page) to the usage made with this API key: the facts whose api_key_id is this value, the key's key_id in the identity API. Read moreUsage made from a console session carries no key and never matches, and neither does usage recorded before the usage fact carried the key (2026-10-06) nor a tool call through the MCP endpoint. A key that made no usage in the window gives a 200 with empty scopes, models and by_principal, zero daily buckets or an empty page, not an error. A value outside the key id grammar renders 400 invalid-request. On the page read the cursor is bound to the filter. The platform operator's summary (platform-usage.read) is not per user: there this filter renders 400 invalid-request. For an API key whose role holds usage.read_own without usage.read, the read is already bound to that key's own id: its own key_id is the same read as no filter, and any other id (of its service account's other keys too) gives a 200 with an empty result. |
operation_classoptional | query | string Optional. Narrows every total, daily bucket and breakdown of the response (or every record of the page) to one class of usage. `inference` is the usage of models: every fact whose operation is not `tool`. `tool` is the calls of MCP tools: the facts whose operation is `tool`, whose model_alias names the installation and the tool. Without it the read covers both, as before. A page's cursor is bound to it. |
Responses
- 200
The selected organization's usage metrics for the requested window.
Schema
UsageSummaryResponseorganization_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,63}$
windowobjectrequiredfromstring (date-time)requiredpattern Z$
tostring (date-time)requiredpattern Z$
scopesarray of UsageSummaryScoperequiredMetrics grouped by accounting_scope; scopes are never combined into an ambiguous total.
accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"recordsUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
request_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
tool_call_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
quantitiesarray of UsageQuantityrequiredmeasurement_countsobjectrequiredmeasuredUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
estimatedUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
outcome_countsobjectrequiredsuccessUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
errorUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
canceledUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
modelsarray of UsageSummaryModelrequiredMetrics grouped by the pair (accounting_scope, model_alias).
accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"recordsUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
request_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
tool_call_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
quantitiesarray of UsageQuantityrequiredmeasurement_countsobjectrequiredmeasuredUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
estimatedUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
outcome_countsobjectrequiredsuccessUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
errorUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
canceledUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
model_aliasstringrequiredOriginal selected model reference, preserved byte-for-byte under the C0 model registry grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
by_principalarray of UsageSummaryPrincipalrequiredMetrics grouped by the pair (accounting_scope, principal_ref): who made the usage of the filtered window, each principal named (see UsageSummaryPrincipal). Ordered by request_count descending (an exact integer), then principal_ref ascending, then accounting_scope. At most 100 entries per accounting_scope (so at most 300): a scope with more principals lists its first 100 and by_principal_truncated is true. The scope totals in scopes always cover every principal.
at most 300 items
accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"recordsUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
request_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
tool_call_countUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
quantitiesarray of UsageQuantityrequiredmeasurement_countsobjectrequiredmeasuredUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
estimatedUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
outcome_countsobjectrequiredsuccessUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
errorUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
canceledUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
unknownUsageCountrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
principal_refstringrequiredThe principal's authoritative reference, preserved byte-for-byte under the C0 identity grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
principal_classstringrequiredAllowed values:
"user""service""agent"emailstring or nullrequiredThe principal's email address, resolved at read time; null when the principal has none (a service account), is unknown to the organization's directory, or this caller may not see another user's email.
at most 254 characters
display_namestring or nullrequiredThe principal's display name (for a service account, its name), resolved at read time; null under the same conditions as email and when the principal has none.
at most 128 characters
by_principal_truncatedbooleanrequiredTrue when at least one accounting scope has more than 100 principals and by_principal lists only its first 100 (ordered by request_count descending, then principal_ref). scopes, models and series always cover every principal.
costobjectrequiredstatusstringrequiredUsage quantities have no authoritative pricing data; no estimated monetary total is presented.
always "unavailable"
seriesarray of UsageSeriesBucketrequiredAscending UTC calendar-day buckets covering the whole half-open response window. First and last bucket boundaries are clipped to the window, including fractional seconds. Every intersecting day is present, including zero days. Within each accounting scope, summing daily metrics and quantities equals the full-window scoped totals; scopes are never added together.
at least 1 items · at most 91 items
windowobjectrequiredfromstring (date-time)requiredpattern Z$
tostring (date-time)requiredpattern Z$
scopesarray of UsageSummaryScoperequiredEach requested accounting scope is present independently. An empty scope has exact zero counts, zero measurement/outcome counts, and quantities []; no units or measurements are fabricated.
at least 1 items · at most 3 items
- 400
Client refusal unrelated to authentication, including malformed input, a denied or failed request.
- 401
The request carries no credential, more than one, or one the platform does not accept, and is refused before the operation runs; `error.code` says why. Supply exactly one credential. Codes: invalid-request (no credential, or both Authorization:
Read more
Bearer and x-api-key), api-key-invalid (a value that is not a platform API key, or a key of a kind the platform does not accept), api-key-unknown, api-key-revoked, api-key-expired, bootstrap-disabled (the one-shot installation credential, once a key exists), token-malformed (a bearer token that is not a JWT), token-algorithm-unsupported, token-signature-invalid, token-claim-invalid, token-issuer-mismatch, token-audience-mismatch, token-expired, token-not-yet-valid, issuer-untrusted, issuer-residency-mismatch (the issuer belongs to another plane), issuer-resolution-unknown, jwks-unavailable, jwks-key-not-found, staff-token-inactive (a platform operator's token), staff-not-operator, staff-directory-unavailable, identity-not-provisioned (a verified identity with no account on this plane), organization-not-found (a verified identity or key whose organization this plane does not know), internal-error (a fault while the credential is checked is refused too, fail closed), context-cancelled
- 402
The organization has to pay first: its standing is payment_required.
Read more
The request boundary applies this payment gate to every route except an organization's billing routes, the caller's own context, organization list, onboarding, session report and personal keys, the public routes, and the routes of platform operators, who administer an organization that has to pay. The operations the gate covers declare this response. On /v1 the refusal is rendered in the OpenAI error format. Code: payment-required
- 403
The credential is valid but may not do this here; the request is refused by the request boundary before the handler runs, and `error.code` says which refusal. An operation may add codes of its own.
Read more
Codes: policy-denied (no role of the caller holds the permission the operation needs, or the credential class may not call it: a personal API key outside inference and MCP, a route that needs a signed-in person, the one-shot installation credential outside its three steps), tenant-mismatch (the organization a path, query, body or X-Tenant header names is not the caller's own), organization-provisioning, organization-suspended, organization-disabled, organization-deleted (the state of the caller's organization), user-disabled, residency-mismatch (the organization lives on another plane), organization-selection-required (a caller with more than one organization, or a platform operator, must name one in X-Organization-Id), organization-not-selectable, no-active-organization-membership, team-not-selectable (the X-Organization-Id or X-Team-Id the caller sent does not name an organization or team it may act in), identity-managed-by-provider (a person who is not a platform operator changes an organization's status, which belongs to the identity provider), support-session-required (a platform operator reads an organization's data without an open support session)
- 405
The path is claimed but the request method is not allowed. Go ServeMux returns its standard plain-text response and lists permitted methods in Allow.
- 500
Platform failure, rendered without internal cause details.
- 503
A dependency the operation needs is not configured on this plane or could not be reached, and nothing was changed. `error.code` names it; an operation lists the ones it can answer besides the boundary's. Retry later. Codes: support-audit-unavailable (the request boundary: an operator's read under an open support session could not be recorded, so nothing was served)
{
"organization_id": "acme",
"window": {
"from": "2026-10-12T00:00:00Z",
"to": "2026-10-14T00:00:00Z"
},
"scopes": [
{
"accounting_scope": "provider_attempt",
"records": "5",
"request_count": "5",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "1840"
},
{
"unit": "output_tokens",
"amount": "3122"
}
],
"measurement_counts": {
"measured": "5",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "4",
"error": "1",
"canceled": "0",
"unknown": "0"
}
}
],
"models": [
{
"accounting_scope": "provider_attempt",
"model_alias": "gpt-4o",
"records": "3",
"request_count": "3",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "1200"
},
{
"unit": "output_tokens",
"amount": "3122"
}
],
"measurement_counts": {
"measured": "3",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "2",
"error": "1",
"canceled": "0",
"unknown": "0"
}
},
{
"accounting_scope": "provider_attempt",
"model_alias": "embed-1",
"records": "2",
"request_count": "2",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "640"
}
],
"measurement_counts": {
"measured": "2",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "2",
"error": "0",
"canceled": "0",
"unknown": "0"
}
}
],
"by_principal": [
{
"accounting_scope": "provider_attempt",
"principal_ref": "svc/01K7YP2C9W4X5E8H3J6M0N1Q2R",
"principal_class": "service",
"email": null,
"display_name": "billing-app",
"records": "5",
"request_count": "5",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "1840"
},
{
"unit": "output_tokens",
"amount": "3122"
}
],
"measurement_counts": {
"measured": "5",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "4",
"error": "1",
"canceled": "0",
"unknown": "0"
}
}
],
"by_principal_truncated": false,
"cost": {
"status": "unavailable"
},
"series": [
{
"window": {
"from": "2026-10-12T00:00:00Z",
"to": "2026-10-13T00:00:00Z"
},
"scopes": [
{
"accounting_scope": "provider_attempt",
"records": "3",
"request_count": "3",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "1000"
},
{
"unit": "output_tokens",
"amount": "1800"
}
],
"measurement_counts": {
"measured": "3",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "3",
"error": "0",
"canceled": "0",
"unknown": "0"
}
}
]
},
{
"window": {
"from": "2026-10-13T00:00:00Z",
"to": "2026-10-14T00:00:00Z"
},
"scopes": [
{
"accounting_scope": "provider_attempt",
"records": "2",
"request_count": "2",
"tool_call_count": "0",
"quantities": [
{
"unit": "input_tokens",
"amount": "840"
},
{
"unit": "output_tokens",
"amount": "1322"
}
],
"measurement_counts": {
"measured": "2",
"estimated": "0",
"unknown": "0"
},
"outcome_counts": {
"success": "1",
"error": "1",
"canceled": "0",
"unknown": "0"
}
}
]
}
]
}/metering/v1/usage/pageList recent usage for the selected organization
- Credential
- API key
- Permission
- Any of
usage.read_ownusage.readsupport-access.read
The organization is derived exclusively from the verified actor context; tenant or organization query parameters are not accepted. Reads occurred_at in a half-open UTC interval and returns a bounded page, in descending occurrence time with deterministic ledger-identity tie breaking.
Read more
The cursor is bound to the organization, frozen window, model filter, accounting-scope filter, principal filter, and API key filter, so a continuation cannot move to another tenant or time range. Counts and quantities preserve exact string values. Unknown or duplicate query parameters, invalid windows, and invalid cursors return 400; a missing selected organization returns 403. An empty window returns records [] and next_cursor null. Optional model_alias, accounting_scope and principal filters (the principal filter takes a principal_ref or an email, like the request-log filter of the same name) apply to the full requested window before aggregation or pagination; filtering never operates on a truncated request page. Requires usage.read_own (at any level) or usage.read. WHICH usage: a caller holding usage.read at organization level (the Administrator role) reads every principal's usage; a caller holding usage.read_own without it - the built-in User role, and a Team Admin, whose usage.read applies to its team's request log and not to this report - reads ONLY the usage whose principal is themselves (a member's own user principal and personal API keys, a service account the usage it made), whatever the request carries: the principal filter is forced to the caller's own reference, so a principal filter naming anyone else, by reference or by email, matches nothing (200 with an empty result, never an error and never a hint of whose usage it is - the request log's narrowing) and by_principal holds only the caller. WITH AN API KEY: these routes answer a service-account API key sent in x-api-key or as Authorization: Bearer, on the console host of the key's own organization and region; a personal API key reaches inference and MCP only and is refused here with 403 policy-denied. A key whose role holds usage.read_own without usage.read reads ONLY the usage made with that key: the facts whose api_key_id is the key's own key_id, not everything its service account made. Whatever the request carries, the read stays bound to that key and to its service account: an api_key_id naming another key (of the same service account or of anyone else) and a principal naming anyone else match nothing (200 with an empty result, never an error), and the key's own id or reference is the same read as no filter. A key whose role holds usage.read at organization level reads the organization's usage exactly as the Administrator role does and may narrow it to one key with api_key_id. Neither level reads another organization: the organization is the key's own and no parameter or header names it. A revoked or expired key is 401 api-key-revoked or api-key-expired, as on every route; an organization with no active subscription is refused with 402 payment-required before any role is checked. For a key reading only its own usage the cursor freezes the key's id and its service account's reference, so a cursor of a read of the organization's usage is refused with 400 invalid-request and a cursor of another key reads nothing. A caller holding neither permission is 403 policy-denied. For a caller reading only their own usage the cursor freezes their own reference as the principal filter, so a cursor minted for a read of everyone's usage (or for anyone else) is refused with 400.
curl "https://console.eu.ccsio.ai/metering/v1/usage/page" \
-H "Authorization: Bearer $CCSIO_API_KEY"Parameters
| Name | In | Description |
|---|---|---|
X-Request-IDoptional | header | string Optional request ULID. A valid ULID (upper or lowercase) is honored; when the header is absent or invalid, the runtime mints the id. The response X-Request-ID header carries the canonical uppercase form. |
fromoptional | query | string Inclusive UTC RFC 3339 start (must end in Z; fractional seconds allowed). Supply both from and to or omit both for the last 7 days, or the cursor's frozen window when paging. The interval must be positive and at most 90 days. |
tooptional | query | string Exclusive UTC RFC 3339 end (must end in Z; fractional seconds allowed). Required when from is supplied. |
model_aliasoptional | query | string Optional exact model reference, preserving case and punctuation. Omit for all models; a valid reference with no matching usage returns empty totals and zero daily buckets. |
accounting_scopeoptional | query | string Optional accounting scope. Omit for all scopes, which remain separate in every aggregate; the literal all is not accepted. |
principaloptional | query | one of Optional. Read moreNarrows every total, daily bucket and breakdown of the response to the usage made by this principal: the principal_ref (a C0 reference) or an email address (it contains '@'), matched case-insensitively against the organization's users and resolved to their refs, exactly as the request-log principal filter does. A reference matches the usage of that principal_ref whatever its principal_class (a member's own sessions and personal API keys share their reference). An email filter follows the visibility rule of the emails themselves: a caller who may not read the organization's member list (members.read at organization level, or a platform administrator) may filter only by their own email, any other address matches no usage; an address that matches no user matches no usage (a 200 with empty scopes, models and by_principal, zero daily buckets or an empty page — not an error — so the filter cannot be used to probe whose address it is). A value that is neither a reference nor a plain email address (no display name, no whitespace, at most 254 bytes) renders 400 invalid-request. On the page read the cursor is bound to the filter as it was typed. The platform operator's summary (platform-usage.read) is not per user: there this filter renders 400 invalid-request. For an API key reading only its own usage, a principal other than its service account's matches no usage. |
api_key_idoptional | query | string Optional. Narrows every total, daily bucket and breakdown of the response (or every record of the page) to the usage made with this API key: the facts whose api_key_id is this value, the key's key_id in the identity API. Read moreUsage made from a console session carries no key and never matches, and neither does usage recorded before the usage fact carried the key (2026-10-06) nor a tool call through the MCP endpoint. A key that made no usage in the window gives a 200 with empty scopes, models and by_principal, zero daily buckets or an empty page, not an error. A value outside the key id grammar renders 400 invalid-request. On the page read the cursor is bound to the filter. The platform operator's summary (platform-usage.read) is not per user: there this filter renders 400 invalid-request. For an API key whose role holds usage.read_own without usage.read, the read is already bound to that key's own id: its own key_id is the same read as no filter, and any other id (of its service account's other keys too) gives a 200 with an empty result. |
operation_classoptional | query | string Optional. Narrows every total, daily bucket and breakdown of the response (or every record of the page) to one class of usage. `inference` is the usage of models: every fact whose operation is not `tool`. `tool` is the calls of MCP tools: the facts whose operation is `tool`, whose model_alias names the installation and the tool. Without it the read covers both, as before. A page's cursor is bound to it. |
limitoptional | query | integer Page size: 1 to 100 records, default 50. Anything else renders 400 invalid-request. |
cursoroptional | query | string Opaque next_cursor from the preceding page. Omitted window and filters reuse the cursor's frozen values; explicitly supplied values must match. Version 2 binds model_alias and accounting_scope as well as organization and window. Legacy version-1 cursors are accepted only for unfiltered continuations. Read moreChanging any filter requires starting without a cursor. A cursor binds the organization, the window and every filter, including api_key_id; for an API key reading only its own usage it also binds the key, so it cannot be used to read another key's records. |
Responses
- 200
A page of usage evidence for the selected organization.
Schema
UsagePageResponseorganization_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,63}$
windowobjectrequiredfromstring (date-time)requiredpattern Z$
tostring (date-time)requiredpattern Z$
recordsarray of RecentUsageRecordrequiredat most 100 items
event_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
occurred_atstring (utc-second)requiredpattern ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$
request_idstringrequiredpattern ^[a-z][a-z0-9._-]{0,127}$
model_aliasstringrequiredOriginal selected model reference, preserved byte-for-byte under the C0 model registry grammar.
pattern ^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$
provider_classanyrequiredAllowed values:
"CCSIO_INFERENCE""CUSTOMER_HOSTED""EXTERNAL_MANAGED"nulloperationstringrequiredAllowed values:
"chat""embedding""audio""image""document""tool""agent_overhead""responses""decision"accounting_scopestringrequiredAllowed values:
"provider_attempt""platform_overhead""agent_aggregate"measurementstringrequiredAllowed values:
"measured""estimated""unknown"outcome_classstringrequiredAllowed values:
"success""error""canceled""unknown"request_duration_msinteger or nullrequiredWhole router request timing, shared by all attempt records; absent on legacy records.
0 to 9007199254740991
quantitiesarray of UsageQuantityrequiredrequest_countstringrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
pattern ^(0|[1-9][0-9]*)$
tool_call_countstringrequiredAn exact non-negative integer serialized as a string to avoid client precision loss.
pattern ^(0|[1-9][0-9]*)$
next_cursorstring or nullrequiredOpaque continuation cursor bound to the selected organization, frozen window, exact model reference and accounting scope; null when there are no more records.
at most 2048 characters
- 400
Client refusal unrelated to authentication, including malformed input, a denied or failed request.
- 401
The request carries no credential, more than one, or one the platform does not accept, and is refused before the operation runs; `error.code` says why. Supply exactly one credential. Codes: invalid-request (no credential, or both Authorization:
Read more
Bearer and x-api-key), api-key-invalid (a value that is not a platform API key, or a key of a kind the platform does not accept), api-key-unknown, api-key-revoked, api-key-expired, bootstrap-disabled (the one-shot installation credential, once a key exists), token-malformed (a bearer token that is not a JWT), token-algorithm-unsupported, token-signature-invalid, token-claim-invalid, token-issuer-mismatch, token-audience-mismatch, token-expired, token-not-yet-valid, issuer-untrusted, issuer-residency-mismatch (the issuer belongs to another plane), issuer-resolution-unknown, jwks-unavailable, jwks-key-not-found, staff-token-inactive (a platform operator's token), staff-not-operator, staff-directory-unavailable, identity-not-provisioned (a verified identity with no account on this plane), organization-not-found (a verified identity or key whose organization this plane does not know), internal-error (a fault while the credential is checked is refused too, fail closed), context-cancelled
- 402
The organization has to pay first: its standing is payment_required.
Read more
The request boundary applies this payment gate to every route except an organization's billing routes, the caller's own context, organization list, onboarding, session report and personal keys, the public routes, and the routes of platform operators, who administer an organization that has to pay. The operations the gate covers declare this response. On /v1 the refusal is rendered in the OpenAI error format. Code: payment-required
- 403
The credential is valid but may not do this here; the request is refused by the request boundary before the handler runs, and `error.code` says which refusal. An operation may add codes of its own.
Read more
Codes: policy-denied (no role of the caller holds the permission the operation needs, or the credential class may not call it: a personal API key outside inference and MCP, a route that needs a signed-in person, the one-shot installation credential outside its three steps), tenant-mismatch (the organization a path, query, body or X-Tenant header names is not the caller's own), organization-provisioning, organization-suspended, organization-disabled, organization-deleted (the state of the caller's organization), user-disabled, residency-mismatch (the organization lives on another plane), organization-selection-required (a caller with more than one organization, or a platform operator, must name one in X-Organization-Id), organization-not-selectable, no-active-organization-membership, team-not-selectable (the X-Organization-Id or X-Team-Id the caller sent does not name an organization or team it may act in), identity-managed-by-provider (a person who is not a platform operator changes an organization's status, which belongs to the identity provider), support-session-required (a platform operator reads an organization's data without an open support session)
- 405
The path is claimed but the request method is not allowed. Go ServeMux returns its standard plain-text response and lists permitted methods in Allow.
- 500
Platform failure, rendered without internal cause details.
- 503
A dependency the operation needs is not configured on this plane or could not be reached, and nothing was changed. `error.code` names it; an operation lists the ones it can answer besides the boundary's. Retry later. Codes: support-audit-unavailable (the request boundary: an operator's read under an open support session could not be recorded, so nothing was served)
{
"organization_id": "acme",
"window": {
"from": "2026-10-12T00:00:00Z",
"to": "2026-10-14T00:00:00Z"
},
"records": [
{
"event_id": "event.req-01k7yqa2c4e6g8j0m2p4r6t8v0",
"occurred_at": "2026-10-13T16:41:02Z",
"request_id": "req-01k7yqa2c4e6g8j0m2p4r6t8v0",
"model_alias": "gpt-4o",
"provider_class": "CCSIO_INFERENCE",
"operation": "chat",
"accounting_scope": "provider_attempt",
"quantities": [
{
"unit": "input_tokens",
"amount": "412"
},
{
"unit": "output_tokens",
"amount": "697"
}
],
"measurement": "measured",
"outcome_class": "success",
"request_duration_ms": 1840,
"request_count": "1",
"tool_call_count": "0"
},
{
"event_id": "event.req-01k7yq5v8n3m4p7r2s6t9w0x1y",
"occurred_at": "2026-10-13T09:14:27Z",
"request_id": "req-01k7yq5v8n3m4p7r2s6t9w0x1y",
"model_alias": "embed-1",
"provider_class": "CCSIO_INFERENCE",
"operation": "embedding",
"accounting_scope": "provider_attempt",
"quantities": [
{
"unit": "input_tokens",
"amount": "320"
}
],
"measurement": "measured",
"outcome_class": "success",
"request_duration_ms": 96,
"request_count": "1",
"tool_call_count": "0"
}
],
"next_cursor": "eyJ2Ijo0LCJ0ZW5hbnQiOiJhY21lIiwid2luZG93Ijp7ImZyb20iOiIyMDI2LTEwLTEyVDAwOjAwOjAwWiIsInRvIjoiMjAyNi0xMC0xNFQwMDowMDowMFoifSwiYWZ0ZXIiOnsiYXQiOiIyMDI2LTEwLTEzVDA5OjE0OjI3WiIsInBsYW5lIjoicGxhbmUuZXUiLCJyZXF1ZXN0IjoicmVxLTAxazd5cTV2OG4zbTRwN3IyczZ0OXcweDF5IiwiYXR0ZW1wdCI6MSwicHJvdmlkZXIiOiJcdTAwM2NudWxsXHUwMDNlIn0sInByaW5jaXBhbCI6InN2Yy8wMUs3WVAyQzlXNFg1RThIM0o2TTBOMVEyUiIsImFwaV9rZXlfaWQiOiIwMUs3WVAzQTVUOFEyTjZSNFYxVzlYWkI3RCJ9"
}Generated from the platform contracts at commit 5f833620.