AI Setu Docs
Operations

Request Log, Export and Retention

Browse, filter and export every request a workspace made, analyse A/B prompt variants, and see how long usage records are kept.

Every request that goes through the gateway leaves one usage record: which model served it, token counts, latency, cost, cache outcome, the metadata tags you sent, and which managed prompt version it used. Prompt and response text is not part of the record.

A workspace can read its own records in three ways: a paginated, filterable request log, an asynchronous export, and per-variant analytics. A common setup is one AI Setu workspace per end customer of yours, so each customer's console shows only that workspace's usage.

All examples use the GraphQL API at https://api.aisetu.ai/graphql, authenticated with a personal access token (Authorization: Bearer $AI_SETU_PAT). Every query is scoped to your organization — a workspace id from another organization returns nothing.

Request log

requestLog returns a workspace's requests newest first. Pages are cursor-based, so walking a large history stays fast and never skips or repeats a row, even while new requests arrive.

query RequestLog($workspaceId: ID!, $after: String) {
  requestLog(
    workspaceId: $workspaceId
    first: 100
    after: $after
    filters: {
      from: "2026-09-01T00:00:00Z"
      to: "2026-09-30T23:59:59Z"
      status: "error"
      model: "gpt-4o"
      tagKey: "customer"
      tagValue: "acme"
    }
  ) {
    entries {
      id
      requestId
      ts
      provider
      model
      status
      latencyMs
      inputTokens
      outputTokens
      cacheReadTokens
      cacheWriteTokens
      cached
      cacheKind
      failoverCount
      costMicros
      metadata {
        key
        value
      }
      promptTemplateId
      promptVersion
      promptExperimentId
    }
    nextCursor
    hasMore
  }
}

To fetch the next page, pass the previous response's nextCursor as after and stop when hasMore is false. first defaults to 50 and is capped at 500.

Filters

Every filter is optional and they combine with AND.

FilterMatches
from, toRequests in this time window (both inclusive)
providerOne provider, e.g. openai, anthropic, bedrock
modelAn exact model id
apiKeyIdRequests made with one API key
tagKeyRequests that carry this metadata tag...
tagKey + tagValue...or carry it with exactly this value
cacheOutcomeHIT (served from cache), MISS, or ALL
statusok, cached, error or cancelled
promptTemplateIdRequests that used one managed prompt template
promptVersionRequests that rendered one template version
promptExperimentIdRequests served by one A/B experiment

Fields

costMicros is the total charged, in USD millionths (1000000 = $1.00), as a string; providerCostMicros and feeMicros are its two parts. metadata is the list of tags sent in the x-ai-setu-metadata header (at most 8), sorted by key. cacheReadTokens and cacheWriteTokens are prompt-cache tokens, reported separately from inputTokens. failoverCount is how many upstream attempts failed before the response was served. origin is null for your own requests; cache_refresh marks the background request that revalidated a stale cache entry.

recentRequests(workspaceId, limit) still exists for a quick look at the newest requests. It returns at most 200 rows, has no filters and no paging — use requestLog for anything more.

Export

For a spreadsheet, a data warehouse load or an audit, export the filtered log as a file. Exports run in the background, so a large history never ties up a request.

mutation StartExport($workspaceId: ID!) {
  requestLogExport(
    workspaceId: $workspaceId
    format: CSV
    filters: { from: "2026-09-01T00:00:00Z", to: "2026-09-30T23:59:59Z" }
  ) {
    id
    status
  }
}

Then poll until status is COMPLETED:

query ExportStatus($id: ID!) {
  requestLogExport(id: $id) {
    id
    status # PENDING -> RUNNING -> COMPLETED | FAILED | EXPIRED
    format
    rowCount
    downloadUrl
    expiresAt
    error
  }
}
curl -o requests.csv "$DOWNLOAD_URL"
  • Formats. NDJSON (default) is one JSON object per line, with the same fields as requestLog and metadata as an object. CSV has a header row and snake_case columns, with metadata as one JSON-encoded column. In CSV, any text value that begins with =, +, - or @ is prefixed with ' so spreadsheet programs show it as text instead of running it as a formula.
  • Snapshot. An export covers requests up to the moment you start it, even if you leave to open, so the file is a stable record.
  • Size limit. One export holds at most 1,000,000 rows. A larger selection is rejected immediately with an error telling you to narrow the time range or filters.
  • One at a time. A workspace can run one export at a time; start the next after the previous one finishes.
  • Download link. downloadUrl is a signed link valid for one hour. Query the export again for a fresh link.
  • Workspace purge. purgeWorkspaceData on a deleted workspace removes its export rows and files immediately (see Data handling).
  • File lifetime. The file itself is deleted 7 days after the export completes (status becomes EXPIRED); run a new export if you need it again.
  • Permission. Starting an export and downloading it requires the data:export permission (Owner and Admin roles by default). Members can read the request log but cannot export.
  • Audit. Each export request is recorded in your organization's audit log with who asked and which filter names were used (not the filter values).

If an export fails, status is FAILED and error says why; starting a new one is always safe.

Analysing A/B prompt variants

When a prompt experiment is running, each request records the template, the version that was served and the experiment. Compare variants with usageBreakdown using the PROMPT_VERSION dimension, narrowed to one experiment:

query VariantComparison($tenantId: ID!) {
  usageBreakdown(
    tenantId: $tenantId
    from: "2026-09-01T00:00:00Z"
    to: "2026-09-30T23:59:59Z"
    dimension: PROMPT_VERSION
    filters: { promptExperimentId: "..." }
  ) {
    key # "<templateId>@<version>"
    label
    requests
    errors
    inputTokens
    outputTokens
    costMicros
    cacheHits
    latencyP95Ms
  }
}

Each row is one variant, keyed <templateId>@<version>. Requests that used no template are grouped as Unattributed.

DimensionGroups by
PROMPTPrompt template
PROMPT_VERSIONTemplate and version — one row per A/B variant
PROMPT_EXPERIMENTA/B experiment id; requests outside any experiment are Unattributed

usageBreakdown and usageSeries accept the same filters object (provider, model, apiKeyId, tagKey/tagValue, cacheOutcome, status, promptTemplateId, promptVersion, promptExperimentId), so the same filters give you a time series for one variant. To see the individual requests behind a variant, use requestLog with the same filters.

Hedging cost

If you send X-AI-Setu-Hedge-After-Ms (see routing), a request can launch a second attempt and cancel the slower one. usageSeries (every bucket), usageBreakdown (every row, for every dimension) and the usage query's rollup carry three counters so you can see what that costs you without scanning the request log:

FieldMeaning
hedgedRequestsRequests where a hedge attempt was launched. Includes requests where both attempts failed.
hedgeWonRequestsRequests the hedge attempt served, because it returned its first token before the primary. Never counts both-failed requests.
hedgeLoserPromptTokensPrompt tokens of the cancelled attempts. 0 when nothing was hedged.

All three are non-null integers. hedgeWonRequests / hedgedRequests is how often the hedge paid off.

Read hedgeLoserPromptTokens as what your provider may bill for cancelled hedges, on top of the winners' usage. AI Setu does not charge for it: the charge on a hedged request is the winner's usage only. It is there so a BYOK account can reconcile its provider invoice. A request where both attempts failed contributes the gateway's prompt estimate for one attempt.

query {
  usageSeries(
    tenantId: "…"
    from: "2026-10-01T00:00:00Z"
    to: "2026-10-22T00:00:00Z"
    bucket: DAY
  ) {
    tsBucket
    requests
    hedgedRequests
    hedgeWonRequests
    hedgeLoserPromptTokens
  }
}

Retention

Usage records are kept for a configurable window. A nightly job deletes records older than the window.

DataKept for
Usage records (the request log)400 days on AI Setu cloud once the retention window is enabled for your deployment; until then, until your organization is deleted
Request-log export files7 days after the export completes
Signed download links1 hour

For self-hosted deployments, the window is the USAGE_EVENTS_RETENTION_DAYS setting. It is off unless you set it, and it must be at least 30 days; a smaller or invalid value is refused and nothing is deleted. Deleting usage records never touches your credit balance or invoices, which are kept separately.

If your own policy requires keeping records longer than the window, export them on a schedule before they age out. For erasure requests, see Data Handling.

On this page