Customer request logs

Package: agentrouter.insights.v1 Service: CustomerRequestLogsService

Endpoints

List request logs scoped to the calling user

Changed in v0.5.0 (deprecations): The microdollar cost fields are deprecated. They have always returned 0, because nothing ever wrote them, and the decimal string fields carry the real amount at full precision. Read total_cost for one request, or cost for a stats group. The fields stay in the API and keep returning 0.

Changed in v0.2.0 (new features): Request-log statistics can now separate spend the organization was actually billed for from cost that is only estimated. Group or filter by usage_mode (managed, byok, passthrough) to keep BYOK and passthrough traffic out of a spend total. Group or filter by usage_source (actual, partial, estimated) to see how much of a figure rests on locally estimated token counts rather than counts the provider reported. Both work on the admin and customer stats endpoints and can be combined with an existing dimension, for example per-model billed spend. usage_mode is available for historical requests; usage_source is recorded from this release onward and is empty for earlier requests, for requests served by a data plane that has not been upgraded, and for rejected or budget-blocked requests. Individual request logs now carry usage_source too, which answers whether a request's token counts were measured or estimated, a question the usage_measured flag cannot answer.

What it does: Returns the caller's own request logs, filtered by the supplied tenancy scope. Forced filter: user_id = caller.UserID.

Request fields:

FieldRequiredDescription
customer_idnoTenancy scope. Defaults to the caller's session customer_id / project_id when empty.
project_idnoProject used to authorize the caller's access (membership check), to resolve session defaults, and to scope the rows: only logs recorded by API keys of the resolved (customer, project) are returned, on top of the forced per-user filter.
api_key_idnoOptional filters. Mirror QueryRequestLogsRequest minus user_id (forced to caller). Restrict to logs produced by this API key (UUID). Superseded by api_key_ids when that field is non-empty.
api_key_idsnoRestrict to logs produced by any of these API keys (UUIDs).
endpointnoRestrict to a single request endpoint (e.g. "/v1/chat/completions").
model_namenoRestrict to a single model name (e.g. "claude-3-opus", "gpt-4").
statusnoRestrict by logical status (e.g. "success", "error", "timeout").
status_codenoRestrict by HTTP status code returned to the client.
start_timenoStart of the time range (inclusive).
end_timenoEnd of the time range (exclusive).
min_duration_msnoOnly include requests at least this many milliseconds long.
max_duration_msnoOnly include requests at most this many milliseconds long.
page_sizenoPagination. Maximum logs per page (server applies a default and cap).
page_tokennoOpaque token from a prior response's next_page_token to fetch the next page.
order_bynoOrdering. Valid order_by: timestamp, duration_ms, input_tokens, output_tokens, total_tokens, total_cost, status_code, model_name, endpoint, api_key_name. Valid order_direction: asc, desc.
order_directionnoSort direction for order_by: "asc" or "desc".
searchnoCase-insensitive literal substring match over request_id.
dataplane_idnoRestrict to logs served by this data plane (the workspace id the reporting dataplane's telemetry is authenticated as, stamped server-side at ingest) -- see RequestLog.dataplane_id.

Response fields:

FieldRequiredDescription
logsnoRequest logs for the caller on this page, newest first by default.
next_page_tokennoToken to pass back as page_token for the next page; empty when exhausted.
total_countnoTotal number of matching logs across all pages (may be approximate).
{"signatures":{"go":"func (x *CustomerRequestLogsClient) ListCustomerRequestLogs(ctx context.Context, req *insightsv1.ListCustomerRequestLogsRequest) (*insightsv1.ListCustomerRequestLogsResponse, error)","python":"list_customer_request_logs(req: request_logs_pb2.ListCustomerRequestLogsRequest) -\u003e ListCustomerRequestLogsResponse","typescript":"listCustomerRequestLogs(req: MessageInitShape\u003ctypeof tars_insights_v1_request_logs_pb.ListCustomerRequestLogsRequestSchema\u003e): Promise\u003cListCustomerRequestLogsResponse\u003e","cli":"tare api insights logs list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tinsightsv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/insights/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026insightsv1.ListCustomerRequestLogsRequest{}\n\n\tresp, err := client.CustomerRequestLogs().ListCustomerRequestLogs(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/customerrequestlogs/listcustomerrequestlogs\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.insights.v1 import request_logs_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = request_logs_pb2.ListCustomerRequestLogsRequest()\ntry:\n    result = client.customer_request_logs.list_customer_request_logs(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.customerRequestLogs.listCustomerRequestLogs(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"customerrequestlogs\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api insights logs list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/request-logs","slug":"list-request-logs-scoped-to-the-calling-user"}

Get a single request log

Changed in v0.5.0 (deprecations): The microdollar cost fields are deprecated. They have always returned 0, because nothing ever wrote them, and the decimal string fields carry the real amount at full precision. Read total_cost for one request, or cost for a stats group. The fields stay in the API and keep returning 0.

Changed in v0.2.0 (new features): Request-log statistics can now separate spend the organization was actually billed for from cost that is only estimated. Group or filter by usage_mode (managed, byok, passthrough) to keep BYOK and passthrough traffic out of a spend total. Group or filter by usage_source (actual, partial, estimated) to see how much of a figure rests on locally estimated token counts rather than counts the provider reported. Both work on the admin and customer stats endpoints and can be combined with an existing dimension, for example per-model billed spend. usage_mode is available for historical requests; usage_source is recorded from this release onward and is empty for earlier requests, for requests served by a data plane that has not been upgraded, and for rejected or budget-blocked requests. Individual request logs now carry usage_source too, which answers whether a request's token counts were measured or estimated, a question the usage_measured flag cannot answer.

What it does: Returns a single request log row owned by the calling user. Cross-user NotFound: the user cannot read another user's log even within the same customer/project.

Request fields:

FieldRequiredDescription
customer_idnoDefaults to the caller's session customer_id / project_id when empty.
project_idnoProject used to authorize the caller's access (membership check), to resolve session defaults, and to scope the lookup: a log recorded by a key outside the resolved (customer, project) is NotFound, matching list visibility.
request_idyesIdentifier of the request log to fetch; must be owned by the caller.

Response fields:

FieldRequiredDescription
idoutput-onlyUnique log identifier
timestampnoTimestamp when the request was received
user_idnoUser ID who made the request
api_key_idnoAPI key information UUID of the API key that authenticated the request.
api_key_prefixnoLeading visible characters of the key (e.g. "sk-..."), for display.
api_key_hashnoHash of the API key used to look it up without storing the secret.
api_key_addressnoOn-chain/account address the API key is bound to.
api_key_namenoHuman-readable label assigned to the API key.
model_namenoModel name used for the request
input_tokensnoToken usage. A zero here is meaningful only when usage_measured is true; when it is false the request never recorded usage (e.g. early failure) and consumers should render these as blank rather than 0. Number of prompt/input tokens consumed by the request.
output_tokensnoNumber of completion/output tokens generated in the response.
input_tokens_cost_microdollarnoCost fields. Every amount below is a decimal string, precision 18, scale 10. An amount is empty when the request never recorded usage. "0" is a real measured zero. total_cost is the field to read. It is the whole billed amount for this request: input + output + additional. Do not add the component fields together. input_tokens_cost already contains the two cache amounts, so a sum of them counts the same money twice. A *_cost field is the amount TARS billed, after the platform fee. The matching *_cost_before_fee field is the provider price, before that fee. The fee rate is a per-deployment setting. On byok and passthrough traffic the customer pays the provider directly, so the billed amount can be the fee alone. Deprecated: always 0. Use input_tokens_cost.
input_tokens_costnoInput-token cost as a decimal string (precision: 18, scale: 10). Empty when usage was never recorded.
input_tokens_cost_before_feenoInput-token cost before the platform fee/markup is applied. Decimal string.
output_tokens_cost_microdollarnoDeprecated: always 0. Use output_tokens_cost.
output_tokens_costnoOutput-token cost as a decimal string (precision: 18, scale: 10). Empty when usage was never recorded.
output_tokens_cost_before_feenoOutput-token cost before the platform fee/markup is applied. Decimal string.
statusnoRequest/Response status Logical outcome of the request (e.g. "success", "error", "timeout").
status_codenoHTTP status code returned to the client.
request_headersnoRequest metadata Captured request headers as a JSON object.
request_bodynoCaptured request payload as a JSON object.
response_headersnoResponse metadata Captured response headers as a JSON object.
response_bodynoText response body captured from the upstream response.
response_body_rawnoRaw response body bytes (for binary payloads such as images).
llm_parametersnoLLM parameters used
upstream_duration_msnoTiming information Duration of the upstream LLM call in milliseconds.
duration_msnoTotal end-to-end request duration in milliseconds.
request_idnoRequest identifier
created_atnoRecord creation timestamp
storage_locationnoObject storage information (for Parquet-based storage) GCS path to the Parquet file when use_object_storage is true.
storage_row_indexnoRow index within the Parquet file.
storage_batch_idnoBatch UUID grouping rows written in the same export batch.
use_object_storagenoTrue when the row is stored in object storage (GCS); false when in the DB.
cached_input_tokensnoCache token breakdown. Meaningful only when cache_measured is true; when it is false the request did not record a cache breakdown and consumers should treat cache-hit as unknown rather than 0%. Cache presence is independent of usage_measured. Input tokens served from the prompt cache (cache reads), billed at the cached rate.
cached_input_tokens_costnoCached-input cost as a decimal string (precision: 18, scale: 10). Empty when cache was never recorded. Part of input_tokens_cost, not an addition to it.
cached_input_tokens_cost_before_feenoCached-input cost before the platform fee/markup is applied. Decimal string.
cache_creation_input_tokensnoInput tokens written to the prompt cache (cache-creation writes).
cache_creation_input_tokens_costnoCache-creation cost as a decimal string (precision: 18, scale: 10). Empty when cache was never recorded. Part of input_tokens_cost, not an addition to it.
cache_creation_input_tokens_cost_before_feenoCache-creation cost before the platform fee/markup is applied. Decimal string.
endpointnoRequest route (e.g. "/v1/chat/completions", "/v1/images/generations").
additional_costnoRequest-level fee after token costs (decimal string, after fee). Empty only when token usage was not measured and no nonzero additional cost was recorded; "0" means a measured real zero fee.
additional_cost_before_feenoRequest-level fee before the platform fee/markup is applied. Empty only when token usage was not measured and no nonzero additional cost was recorded; "0" means a measured real zero fee.
total_costnoTotal billed cost after fee: input + output + additional. Empty only when token usage was not measured and no nonzero additional cost was recorded.
model_requestednoModel name the client requested (from request headers/body).
model_effectivenoModel name that actually served the request (after routing/fallback).
used_fallback_modelnoTrue when the gateway substituted a fallback model for the request.
used_byoknoTrue when the request used bring-your-own-key (customer-supplied provider key).
used_passthroughnoTrue when the request was forwarded in passthrough mode without rewriting.
is_provider_fallbacknoTrue when the provider itself returned a fallback model.
usage_measurednoPresence signals for the nullable metric groups above. A real 0 is indistinguishable from "never recorded" on the integer fields, so these tell consumers whether those zero values are measured. True when the request recorded token usage (input/output tokens + costs).
cache_measurednoTrue when the request recorded a prompt-cache breakdown (cached and cache-creation tokens). Independent of usage_measured.
dataplane_idnoIdentity of the DATA PLANE that served (and reported) this request: the workspace id the reporting dataplane's telemetry channel is authenticated as (project_gateways.workspace_id), stamped server-side at telemetry ingest from the MP-verified service-account binding -- not from request headers or reporter-supplied claims -- so attribution survives customer-managed DNS failover between a project's member gateways. NOTE: this is dataplane granularity, not per-gateway -- gateways co-located on one dataplane share a value (true per-gateway attribution requires the dataplane to export its per-request P10 gateway match and is tracked as a follow-up). Empty for rows recorded before dataplane attribution existed and for deployments that write logs locally without a reporting identity.
usage_sourcenoHow this row's token counts were obtained: "actual" (the provider reported usage), "partial" (input real, output estimated), "estimated" (no usage at all, e.g. a cancelled stream). This is the field that answers "are these token counts real?", which usage_measured cannot: on an estimated row the estimator writes its guess into the usage fields, so usage_measured reports true wherever that guess is non-zero. (A zero estimate leaves the token fields unset and usage_measured false, so it is not a reliable inverse either.) Empty means no usage was resolved for this request. That covers rows predating the field and rows from a data plane not yet upgraded, and permanently covers rejected and budget-blocked requests.
{"signatures":{"go":"func (x *CustomerRequestLogsClient) GetCustomerRequestLog(ctx context.Context, req *insightsv1.GetCustomerRequestLogRequest) (*insightsv1.RequestLog, error)","python":"get_customer_request_log(req: request_logs_pb2.GetCustomerRequestLogRequest) -\u003e RequestLog","typescript":"getCustomerRequestLog(req: MessageInitShape\u003ctypeof tars_insights_v1_request_logs_pb.GetCustomerRequestLogRequestSchema\u003e): Promise\u003cRequestLog\u003e","cli":"tare api insights logs get --request-id $REQUEST_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tinsightsv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/insights/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026insightsv1.GetCustomerRequestLogRequest{}\n\n\tresp, err := client.CustomerRequestLogs().GetCustomerRequestLog(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/customerrequestlogs/getcustomerrequestlog\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.insights.v1 import request_logs_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = request_logs_pb2.GetCustomerRequestLogRequest()\ntry:\n    result = client.customer_request_logs.get_customer_request_log(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.customerRequestLogs.getCustomerRequestLog(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"customerrequestlogs\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api insights logs get --request-id $REQUEST_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/request-logs/{request_id}","slug":"get-a-single-request-log"}

Aggregate stats over the caller's request logs

Changed in v0.5.0 (bug fixes): Request log stats now report the full billed amount. The group cost left out per-image generation cost, so a group of image generation traffic could read 0.00 while those requests were billed. The response-level total cost was never populated and was always empty. Both now count every cost component, so figures for image-heavy workloads rise to the amount that was always charged.

Changed in v0.5.0 (deprecations): The microdollar cost fields are deprecated. They have always returned 0, because nothing ever wrote them, and the decimal string fields carry the real amount at full precision. Read total_cost for one request, or cost for a stats group. The fields stay in the API and keep returning 0.

Changed in v0.2.0 (new features): Request-log statistics can now separate spend the organization was actually billed for from cost that is only estimated. Group or filter by usage_mode (managed, byok, passthrough) to keep BYOK and passthrough traffic out of a spend total. Group or filter by usage_source (actual, partial, estimated) to see how much of a figure rests on locally estimated token counts rather than counts the provider reported. Both work on the admin and customer stats endpoints and can be combined with an existing dimension, for example per-model billed spend. usage_mode is available for historical requests; usage_source is recorded from this release onward and is empty for earlier requests, for requests served by a data plane that has not been upgraded, and for rejected or budget-blocked requests. Individual request logs now carry usage_source too, which answers whether a request's token counts were measured or estimated, a question the usage_measured flag cannot answer.

What it does: Returns aggregated statistics over the calling user's request logs within the supplied tenancy scope.

Request fields:

FieldRequiredDescription
customer_idnoDefaults to the caller's session customer_id / project_id when empty.
project_idnoProject used to authorize the caller's access (membership check), to resolve session defaults, and to scope the aggregation: only the caller's logs recorded by API keys of the resolved (customer, project) are counted.
model_namenoOptional filter restricting stats to a single model name.
start_timenoStart of the aggregation time range (inclusive).
end_timenoEnd of the aggregation time range (exclusive).
group_bynoDimension to group by: "model", "user", "api_key", "status", "dataplane", "usage_mode", "usage_source", "hour", "day". Grouping by "dataplane" keys each StatEntry by the reporting dataplane's identity (see RequestLog.dataplane_id -- gateways co-located on one dataplane share a bucket); rows recorded before dataplane attribution existed group under the empty key "". Grouping by "usage_mode" keys each StatEntry by how the request was paid for: "managed" (billed by TARS per token), "byok" (the customer's own provider credential) or "passthrough" (the caller's own subscription). Cost on a byok or passthrough group is a token-priced ESTIMATE, not a charge. Derived from the upstream-backend response header, so it is available for the full history; a row whose header is absent (client cancel, upstream error, or a gateway-side 4xx before routing) currently groups under "managed" -- see tetrateio/fraser#5166. Cost on a byok or passthrough group means what TARS billed, which is deployment-dependent and differs from what the usage dashboard shows for the same requests -- see the StatEntry.cost comment before comparing the two. Grouping by "usage_source" splits a group into measured versus estimated usage: "actual" (the provider reported usage), "partial" (input real, output estimated), "estimated" (no usage at all, e.g. a cancelled stream). Rows for which no usage was resolved group under the empty key "". That bucket does NOT drain over time: as well as rows predating this dimension and rows from a data plane not yet upgraded, it permanently contains rejected and budget-blocked requests, which never reach usage resolution.
metricnoMetric to compute: "count", "tokens", "cost", "latency", "errors".
dataplane_idnoOptional filter restricting stats to logs served by this data plane (see RequestLog.dataplane_id). Empty means "no filter" -- the unattributed "" bucket surfaced by group_by="dataplane" cannot be selected here.
usage_modenoOptional filter restricting stats to one billing mode: "managed", "byok" or "passthrough" (see group_by). Empty means "no filter"; any other value is rejected with InvalidArgument rather than matching nothing, because an empty result reads as "no traffic in this mode". Combine with group_by to cross-cut, e.g. group_by="model" with usage_mode="managed" for per-model actual spend.
usage_sourcenoOptional filter restricting stats to one usage source: "actual", "partial" or "estimated" (see group_by). Empty means "no filter"; any other value is rejected with InvalidArgument. The "" bucket surfaced by group_by="usage_source" cannot be selected here.

Response fields:

FieldRequiredDescription
statsnoStatistics grouped by the requested dimension
total_countnoTotal counts across all groups Total number of requests across all groups.
total_input_tokensnoSum of input tokens across all groups.
total_output_tokensnoSum of output tokens across all groups.
total_costnoTotal billed cost across all groups as a decimal string.
avg_duration_msnoMean request duration in milliseconds across all groups.
error_countnoTotal number of error requests across all groups.
total_cached_input_tokensnoSum of input tokens served from the prompt cache (cache reads) across all groups.
total_cache_creation_input_tokensnoSum of input tokens written to the prompt cache (cache-creation writes) across all groups.
{"signatures":{"go":"func (x *CustomerRequestLogsClient) GetCustomerRequestLogStats(ctx context.Context, req *insightsv1.GetCustomerRequestLogStatsRequest) (*insightsv1.RequestLogStatsResponse, error)","python":"get_customer_request_log_stats(req: request_logs_pb2.GetCustomerRequestLogStatsRequest) -\u003e RequestLogStatsResponse","typescript":"getCustomerRequestLogStats(req: MessageInitShape\u003ctypeof tars_insights_v1_request_logs_pb.GetCustomerRequestLogStatsRequestSchema\u003e): Promise\u003cRequestLogStatsResponse\u003e","cli":"tare api insights logs stats","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs/stats\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tinsightsv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/insights/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026insightsv1.GetCustomerRequestLogStatsRequest{}\n\n\tresp, err := client.CustomerRequestLogs().GetCustomerRequestLogStats(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/customerrequestlogs/getcustomerrequestlogstats\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.insights.v1 import request_logs_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = request_logs_pb2.GetCustomerRequestLogStatsRequest()\ntry:\n    result = client.customer_request_logs.get_customer_request_log_stats(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.customerRequestLogs.getCustomerRequestLogStats(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"customerrequestlogs\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api insights logs stats","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../request-logs/stats\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/request-logs/stats","slug":"aggregate-stats-over-the-callers-request-logs"}