---
title: AI Gateway Custom Reporting API
product: vercel
url: /docs/ai-gateway/observability-and-spend/custom-reporting
canonical_url: "https://vercel.com/docs/ai-gateway/observability-and-spend/custom-reporting"
last_updated: 2026-09-08
type: reference
prerequisites:
  - /docs/ai-gateway/observability-and-spend
  - /docs/ai-gateway
related:
  - /docs/ai-gateway/sdks-and-apis
  - /docs/ai-gateway/models-and-providers/provider-options
  - /docs/ai-gateway/authentication-and-byok/api-keys
summary: Query AI Gateway usage data grouped by model, user, tag, provider, or credential type using the Custom Reporting API.
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

# AI Gateway Custom Reporting API

The Custom Reporting API gives you detailed visibility into your AI Gateway usage. You can break down costs and token consumption by model, user, tag, provider, or credential type to understand exactly where your AI spend is going.


<!-- docsgraph:related -->
## Related pages

> **For AI agents:** Follow these links to understand how this page connects to the rest of the Vercel ecosystem. For the full cross-link map (inbound, outbound, prerequisites, and semantic neighbors), see the .graph.md link below.

- [How to architect an AI evaluation dashboard on Vercel](https://vercel.com/kb/guide/ai-evaluation-dashboard-architecture-on-vercel?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — Map eval orchestration, traces, and run storage to AI Gateway, Observability, and Marketplace Postgres, and learn when s
- [How to build your own AI model router](https://vercel.com/kb/guide/how-to-build-your-own-ai-model-router?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — Build an AI model router with Vercel AI Gateway. Keep routing, key, and retention decisions in your code while the gatew
- [Unified reporting for all AI Gateway usage](https://vercel.com/blog/unified-reporting-for-your-ai-spend?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related)
- [Custom reporting now available on AI Gateway](https://vercel.com/changelog/custom-reporting-ai-gateway?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related)
- [Get Usage Report](https://v0.app/docs/api/v1/reference/reports/get-usage?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — Retrieves detailed usage events for the authenticated user or team, including costs, event types, models used, and metad
- [AI Gateway production index](https://vercel.com/blog/ai-gateway-production-index?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related)
- [Query Reference](https://vercel.com/docs/query/reference?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — This reference covers the dimensions and operators used to create a query.
- [Aggregates page views](https://vercel.com/docs/rest-api/web-analytics/aggregates-page-views?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — GET /v1/query/web-analytics/visits/aggregate — Counts pageviews on a project, within the requested date range. Results a
- [Query Web Analytics with the API](https://vercel.com/docs/analytics/web-analytics-api?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — Learn how Web Analytics concepts map to API queries for custom reports, dashboards, and insights.
- [Aggregates custom events](https://vercel.com/docs/rest-api/web-analytics/aggregates-custom-events?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — GET /v1/query/web-analytics/events/aggregate — Counts custom events on a project, within the requested date range. Resul
- [Monitoring Reference](https://vercel.com/docs/query/monitoring/monitoring-reference?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=related) — This reference covers the clauses, fields, and variables used to create a Monitoring query.

Full cross-link map for this page: [/docs/ai-gateway/observability-and-spend/custom-reporting.graph.md](/docs/ai-gateway/observability-and-spend/custom-reporting.graph.md?from=related&source_path=%2Fdocs%2Fai-gateway%2Fobservability-and-spend%2Fcustom-reporting&source_site=vercel-docs&relationship=graph)
<!-- /docsgraph:related -->

Use it to:

- **Track costs by model**: See how much you're spending on each model and compare cost efficiency across providers
- **Monitor per-user usage**: Identify which users are driving the most spend and token consumption
- **Analyze by tags**: Tag requests by feature, environment, or team to attribute costs and track usage across your organization
- **Compare providers**: Understand cost and usage differences between providers serving the same models
- **Audit BYOK vs system credentials**: Break down usage by credential type to see the impact of bring-your-own-key requests

> **💡 Note:** The API is currently scoped to your entire account, so the API key you use
> will return usage data for everything on the account.

## Pricing

| Charge type | Cost                                         |
| ----------- | -------------------------------------------- |
| Write       | $0.075 / 1,000 tag/user ID writes            |
| Query       | $5 / 1,000 queries to the reporting endpoint |

> **💡 Note:** Each unique tag or user ID within a single request scope counts as one write.

## Applying user and tag info to requests

To use reporting, attach a `user` and/or `tags` to your AI Gateway requests. You can do this through the AI SDK, Chat Completions API, Responses API, OpenResponses API, or Anthropic Messages API. For Chat Completions, the standard `user` field supplies the reporting user when `providerOptions.gateway.user` is not set.

These examples use AI SDK 7 and the AI SDK for Python beta. Set `AI_GATEWAY_API_KEY` before running them. See [API format differences](/docs/ai-gateway/sdks-and-apis#api-format-differences) for setup, request fields, and response handling.

#### AI SDK

#### TypeScript

See the [AI SDK usage-tracking reference](https://ai-sdk.dev/providers/ai-sdk-providers/ai-gateway#usage-tracking-with-user-and-tags) for SDK configuration and usage.

```typescript filename="custom-reporting.ts"
import { generateText } from 'ai';

const { text } = await generateText({
  model: 'anthropic/claude-sonnet-5',
  prompt: 'Tell me about San Francisco.',
  providerOptions: {
    gateway: {
      user: 'user-123',
      tags: ['feature:chat', 'env:development'],
    },
  },
});

console.log(text);
```

#### Python (beta)

```python filename="custom-reporting_ai.py"
import asyncio
import ai

async def main():
    model = ai.get_model("anthropic/claude-sonnet-5")
    messages = [ai.user_message("Tell me about San Francisco.")]
    params = ai.InferenceRequestParams(
        extra_body={"providerOptions": {"gateway": {"user": "user-123", "tags": ["feature:chat", "env:development"]}}}
    )
    async with ai.stream(model, messages, params=params) as stream:
        async for event in stream:
            if isinstance(event, ai.events.TextDelta):
                print(event.chunk, end="", flush=True)
    print()

asyncio.run(main())
```

#### Chat Completions

#### TypeScript

```typescript filename="custom-reporting-chat.ts"
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh/v1',
});

const response = await client.chat.completions.create({
  model: 'anthropic/claude-sonnet-5',
  messages: [
    {
      role: 'user',
      content: 'Tell me about San Francisco.',
    },
  ],
  // AI Gateway extension fields are not included in the upstream SDK types.
  ...{
    providerOptions: {
      gateway: {
        user: 'user-123',
        tags: ['feature:chat', 'env:development'],
      },
    },
  },
});

console.log(response.choices[0]?.message.content);
```

#### Python

```python filename="custom-reporting_chat.py"
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh/v1",
)

response = client.chat.completions.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Tell me about San Francisco."}],
    extra_body={"providerOptions": {"gateway": {"user": "user-123", "tags": ["feature:chat", "env:development"]}}},
)

print(response.choices[0].message.content)
```

#### cURL

```bash filename="custom-reporting-chat.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/chat/completions \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "messages": [
    {
      "role": "user",
      "content": "Tell me about San Francisco."
    }
  ],
  "providerOptions": {
    "gateway": {
      "user": "user-123",
      "tags": [
        "feature:chat",
        "env:development"
      ]
    }
  }
}'
```

#### Messages API

#### TypeScript

```typescript filename="custom-reporting-messages.ts"
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh',
});

const response = await client.messages.create({
  model: 'anthropic/claude-sonnet-5',
  messages: [
    {
      role: 'user',
      content: 'Tell me about San Francisco.',
    },
  ],
  max_tokens: 1024,
  ...{
    providerOptions: {
      gateway: {
        user: 'user-123',
        tags: ['feature:chat', 'env:development'],
      },
    },
  },
});

for (const block of response.content) {
  if (block.type === 'text') console.log(block.text);
}
```

#### Python

```python filename="custom-reporting_messages.py"
import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh",
)

response = client.messages.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Tell me about San Francisco."}],
    max_tokens=1024,
    extra_body={"providerOptions": {"gateway": {"user": "user-123", "tags": ["feature:chat", "env:development"]}}},
)

for block in response.content:
    if block.type == "text":
        print(block.text)
```

#### cURL

```bash filename="custom-reporting-messages.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/messages \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "messages": [
    {
      "role": "user",
      "content": "Tell me about San Francisco."
    }
  ],
  "max_tokens": 1024,
  "providerOptions": {
    "gateway": {
      "user": "user-123",
      "tags": [
        "feature:chat",
        "env:development"
      ]
    }
  }
}'
```

#### Responses / OpenResponses

#### TypeScript

```typescript filename="custom-reporting-responses.ts"
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh/v1',
});

const response = await client.responses.create({
  model: 'anthropic/claude-sonnet-5',
  input: 'Tell me about San Francisco.',
  ...{
    providerOptions: {
      gateway: {
        user: 'user-123',
        tags: ['feature:chat', 'env:development'],
      },
    },
  },
});

console.log(response.output_text);
```

#### Python

```python filename="custom-reporting_responses.py"
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh/v1",
)

response = client.responses.create(
    model="anthropic/claude-sonnet-5",
    input="Tell me about San Francisco.",
    extra_body={"providerOptions": {"gateway": {"user": "user-123", "tags": ["feature:chat", "env:development"]}}},
)

print(response.output_text)
```

#### cURL

```bash filename="custom-reporting-responses.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/responses \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "input": "Tell me about San Francisco.",
  "providerOptions": {
    "gateway": {
      "user": "user-123",
      "tags": [
        "feature:chat",
        "env:development"
      ]
    }
  }
}'
```

### Using HTTP headers

You can also send reporting metadata as HTTP headers instead of (or in addition to) `providerOptions.gateway`. This is useful when a platform or proxy layer stamps context onto traffic without modifying application code:

| Header              | Type   | Behavior when the request body also sets the same field                               |
| ------------------- | ------ | ------------------------------------------------------------------------------------- |
| `ai-reporting-tags` | string | Comma-separated list. **Merged** with `providerOptions.gateway.tags` (deduped union). |
| `ai-reporting-user` | string | Single value. **Overwrites** `providerOptions.gateway.user` when present.             |

Validation limits match the body schema: up to 10 tags total after merging header and body values (deduped), with each tag between 1 and 64 characters; `user` up to 256 characters. An invalid header returns HTTP `400`.

Both headers work across AI Gateway endpoints that accept `providerOptions.gateway`, including the formats shown below. The `defaultHeaders` / `default_headers` pattern on the SDK client is the same regardless of which endpoint you call. Swap in `responses.create`, `messages.create`, embeddings, image generation, or other supported calls as needed.

#### Request examples

#### AI SDK

#### TypeScript

```typescript filename="reporting-headers.ts"
import { generateText } from 'ai';

const { text } = await generateText({
  model: 'anthropic/claude-sonnet-5',
  prompt: 'Explain quantum computing in two sentences.',
  headers: {
    'ai-reporting-tags': 'team:billing,feature:chat,env:development',
    'ai-reporting-user': 'user-12345',
  },
});

console.log(text);
```

#### Python (beta)

```python filename="reporting-headers_ai.py"
import asyncio
import ai

async def main():
    model = ai.get_model("anthropic/claude-sonnet-5")
    messages = [ai.user_message("Explain quantum computing in two sentences.")]
    params = ai.InferenceRequestParams(
        extra_headers={"ai-reporting-tags": "team:billing,feature:chat,env:development", "ai-reporting-user": "user-12345"}
    )
    async with ai.stream(model, messages, params=params) as stream:
        async for event in stream:
            if isinstance(event, ai.events.TextDelta):
                print(event.chunk, end="", flush=True)
    print()

asyncio.run(main())
```

#### Chat Completions

#### TypeScript

```typescript filename="reporting-headers-chat.ts"
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh/v1',
  defaultHeaders: {
    'ai-reporting-tags': 'team:billing,feature:chat,env:development',
    'ai-reporting-user': 'user-12345',
  },
});

const response = await client.chat.completions.create({
  model: 'anthropic/claude-sonnet-5',
  messages: [
    {
      role: 'user',
      content: 'Explain quantum computing in two sentences.',
    },
  ],
});

console.log(response.choices[0]?.message.content);
```

#### Python

```python filename="reporting-headers_chat.py"
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh/v1",
    default_headers={"ai-reporting-tags": "team:billing,feature:chat,env:development", "ai-reporting-user": "user-12345"},
)

response = client.chat.completions.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Explain quantum computing in two sentences."}],
)

print(response.choices[0].message.content)
```

#### cURL

```bash filename="reporting-headers-chat.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/chat/completions \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "ai-reporting-tags: team:billing,feature:chat,env:development" \
  -H "ai-reporting-user: user-12345" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "messages": [
    {
      "role": "user",
      "content": "Explain quantum computing in two sentences."
    }
  ]
}'
```

#### Messages API

#### TypeScript

```typescript filename="reporting-headers-messages.ts"
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh',
  defaultHeaders: {
    'ai-reporting-tags': 'team:billing,feature:chat,env:development',
    'ai-reporting-user': 'user-12345',
  },
});

const response = await client.messages.create({
  model: 'anthropic/claude-sonnet-5',
  messages: [
    {
      role: 'user',
      content: 'Explain quantum computing in two sentences.',
    },
  ],
  max_tokens: 1024,
});

for (const block of response.content) {
  if (block.type === 'text') console.log(block.text);
}
```

#### Python

```python filename="reporting-headers_messages.py"
import os
from anthropic import Anthropic

client = Anthropic(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh",
    default_headers={"ai-reporting-tags": "team:billing,feature:chat,env:development", "ai-reporting-user": "user-12345"},
)

response = client.messages.create(
    model="anthropic/claude-sonnet-5",
    messages=[{"role": "user", "content": "Explain quantum computing in two sentences."}],
    max_tokens=1024,
)

for block in response.content:
    if block.type == "text":
        print(block.text)
```

#### cURL

```bash filename="reporting-headers-messages.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/messages \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -H "ai-reporting-tags: team:billing,feature:chat,env:development" \
  -H "ai-reporting-user: user-12345" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "messages": [
    {
      "role": "user",
      "content": "Explain quantum computing in two sentences."
    }
  ],
  "max_tokens": 1024
}'
```

#### Responses / OpenResponses

#### TypeScript

```typescript filename="reporting-headers-responses.ts"
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.AI_GATEWAY_API_KEY,
  baseURL: 'https://ai-gateway.vercel.sh/v1',
  defaultHeaders: {
    'ai-reporting-tags': 'team:billing,feature:chat,env:development',
    'ai-reporting-user': 'user-12345',
  },
});

const response = await client.responses.create({
  model: 'anthropic/claude-sonnet-5',
  input: 'Explain quantum computing in two sentences.',
});

console.log(response.output_text);
```

#### Python

```python filename="reporting-headers_responses.py"
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["AI_GATEWAY_API_KEY"],
    base_url="https://ai-gateway.vercel.sh/v1",
    default_headers={"ai-reporting-tags": "team:billing,feature:chat,env:development", "ai-reporting-user": "user-12345"},
)

response = client.responses.create(
    model="anthropic/claude-sonnet-5",
    input="Explain quantum computing in two sentences.",
)

print(response.output_text)
```

#### cURL

```bash filename="reporting-headers-responses.sh"
curl --fail-with-body https://ai-gateway.vercel.sh/v1/responses \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "ai-reporting-tags: team:billing,feature:chat,env:development" \
  -H "ai-reporting-user: user-12345" \
  -d '{
  "model": "anthropic/claude-sonnet-5",
  "input": "Explain quantum computing in two sentences."
}'
```

## Custom Reporting API reference

The reporting endpoint is available on Pro and Enterprise plans. The team is inferred from the API key or OIDC token. Hobby and Pro-trial plans cannot use this endpoint.

### Endpoint

```http filename="Endpoint"
GET https://ai-gateway.vercel.sh/v1/report
```

### Authentication

All requests require a Bearer token in the `Authorization` header:

```bash
Authorization: Bearer YOUR_API_KEY
```

### Required query parameters

| Parameter    | Type   | Description                       |
| ------------ | ------ | --------------------------------- |
| `start_date` | string | Start date in `YYYY-MM-DD` format |
| `end_date`   | string | End date in `YYYY-MM-DD` format   |

Dates are inclusive (both `start_date` and `end_date` are included) and in UTC.

### Optional query parameters

#### Grouping

| Parameter   | Type   | Options                                                                                                                                                                                     | Description                                                                                               |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `group_by`  | string | `day` (default), `user`, `model`, `tag`, [`provider`](/docs/ai-gateway/models-and-providers/provider-options#available-providers), `credential_type`, `zero_data_retention`, `api_key_name` | How to aggregate the results. Each row represents one bucket of this dimension.                           |
| `date_part` | string | `day` (default), `hour`                                                                                                                                                                     | Time granularity. Only applies when `group_by=day`. Use `hour` for per-hour rows, `day` for per-day rows. |

#### Filtering

Filters are applied before aggregation. Combine them with any `group_by` value.

| Parameter             | Type    | Description                                                                                                                      | Example                          |
| --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| `api_key_id`          | string  | Filter by a stable API key ID. Use `self` for the AI Gateway API key that authenticated the report request.                      | `abc123` or `self`               |
| `user_id`             | string  | Filter by a specific user ID                                                                                                     | `user_123`                       |
| `model`               | string  | Filter by a specific [model](/ai-gateway/models) in `creator/model-name` format                                                  | `anthropic/claude-sonnet-5`      |
| `provider`            | string  | Filter by [provider](/docs/ai-gateway/models-and-providers/provider-options#available-providers)                                 | `openai`                         |
| `credential_type`     | string  | Filter by credential type                                                                                                        | `byok` or `system`               |
| `zero_data_retention` | boolean | Filter to Zero Data Retention (ZDR)-requested vs non-ZDR requests                                                                | `true` or `false`                |
| `tags`                | string  | Filter by one or more comma-separated tags. By default, requests match when they contain any listed tag.                         | `production` or `production,api` |
| `tags_match`          | string  | Match mode for `tags`. Use `any` to match requests with any listed tag, or `all` to require every listed tag. Defaults to `any`. | `any` or `all`                   |

API key names are not unique, so use the stable key ID when filtering. [List the team's API keys](/docs/ai-gateway/authentication-and-byok/api-keys#view-a-key) to find each key's `id`. If you omit `api_key_id`, the report includes spend across the team. `self` requires AI Gateway API key authentication. The API returns a `400` response if you use `self` with an OIDC token, personal access token, or app token.

### Example request

```bash filename="terminal"
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&group_by=model" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY"
```

### Response format

The API returns a JSON object with a `results` array. Each row contains the one grouping field that matches the `group_by` parameter you used, plus the aggregated metrics. The example below shows every possible field together so you can see the shape; in a real response, only the grouping field for your selected `group_by` will be present. It can take a few minutes for requests to appear in the reporting endpoint.

```json filename="Response"
{
  "results": [
    {
      "day": "2026-01-01",
      "model": "anthropic/claude-sonnet-5",
      "provider": "anthropic",
      "user": "user_123",
      "tag": "production",
      "credential_type": "system",
      "zero_data_retention": "false",
      "api_key_name": "Production key",
      "total_cost": 10.5,
      "market_cost": 12.0,
      "surcharge_cost": 0.5,
      "gateway_cost": 0,
      "input_tokens": 1000,
      "output_tokens": 500,
      "cached_input_tokens": 200,
      "cache_creation_input_tokens": 50,
      "reasoning_tokens": 100,
      "request_count": 25
    }
  ]
}
```

### Response fields

Every row includes a single grouping field that depends on `group_by`, plus the metrics below.

#### Grouping fields

| Field                 | Present when                                 | Type   | Notes                                                          |
| --------------------- | -------------------------------------------- | ------ | -------------------------------------------------------------- |
| `day`                 | `group_by=day` and `date_part=day` (default) | string | The UTC date for the bucket (`YYYY-MM-DD`)                     |
| `hour`                | `group_by=day` and `date_part=hour`          | string | The UTC hour for the bucket (`YYYY-MM-DDTHH`)                  |
| `user`                | `group_by=user`                              | string | The user ID attached to the request                            |
| `model`               | `group_by=model`                             | string | The model in `creator/model-name` form                         |
| `tag`                 | `group_by=tag`                               | string | A single tag value (one row per tag in the request)            |
| `provider`            | `group_by=provider`                          | string | The provider that served the request                           |
| `credential_type`     | `group_by=credential_type`                   | string | `byok` or `system`                                             |
| `zero_data_retention` | `group_by=zero_data_retention`               | string | `true` or `false`                                              |
| `api_key_name`        | `group_by=api_key_name`                      | string | The human-readable name of the API key that served the request |

#### Metric fields

| Field                         | Type   | Description                                                                           |
| ----------------------------- | ------ | ------------------------------------------------------------------------------------- |
| `total_cost`                  | number | Charged price in USD. Returns `0.00` for BYOK requests.                               |
| `market_cost`                 | number | Market price of the request at the time it ran. Includes both BYOK and non-BYOK cost. |
| `surcharge_cost`              | number | Surcharge portion of `total_cost` (for example, from add-on capabilities).            |
| `gateway_cost`                | number | AI Gateway's own cost, separate from the provider rate.                               |
| `input_tokens`                | number | Input tokens used                                                                     |
| `output_tokens`               | number | Output tokens used                                                                    |
| `cached_input_tokens`         | number | Cached input tokens                                                                   |
| `cache_creation_input_tokens` | number | Cache creation tokens                                                                 |
| `reasoning_tokens`            | number | Reasoning tokens                                                                      |
| `request_count`               | number | Number of requests in this row                                                        |

All cost values are in USD and aggregated based on the grouping parameter.

## Querying reports with the AI SDK

Query spend reports with the AI SDK's `getSpendReport()` method. It accepts the same parameters as the REST API (in camelCase) and returns camelCase results.

```typescript
import { gateway } from 'ai';

const report = await gateway.getSpendReport({
  startDate: '2026-03-01',
  endDate: '2026-03-25',
  groupBy: 'model',
});

for (const row of report.results) {
  console.log(`${row.model}: $${row.totalCost.toFixed(4)}`);
}
```

You can combine tagging on requests with filtered queries to attribute costs by feature, team, or environment:

```typescript
import type { GatewayProviderOptions } from '@ai-sdk/gateway';
import { gateway, streamText } from 'ai';

// 1. Make requests with tags
const result = streamText({
  model: 'anthropic/claude-opus-5',
  prompt: "Summarize this quarter's results",
  providerOptions: {
    gateway: {
      tags: ['team:finance', 'feature:summaries'],
    } satisfies GatewayProviderOptions,
  },
});

// 2. Later, query spend filtered by those tags
const report = await gateway.getSpendReport({
  startDate: '2026-03-01',
  endDate: '2026-03-31',
  groupBy: 'tag',
  tags: ['team:finance'],
});

for (const row of report.results) {
  console.log(
    `${row.tag}: $${row.totalCost.toFixed(4)} (${row.requestCount} requests)`,
  );
}
```

See the [AI SDK docs on spend reports](https://ai-sdk.dev/providers/ai-sdk-providers/ai-gateway#querying-spend-reports) for the full list of parameters and response fields.

## Generation lookup

Use the AI SDK's `getGenerationInfo()` method to look up a specific generation by its ID, including cost, token usage, latency, and provider details. Generation IDs are available in `providerMetadata.gateway.generationId` on both `generateText` and `streamText` responses.

When streaming, the generation ID is injected on the first content chunk, so you can capture it early without waiting for completion. This is useful when a network interruption cuts off the final response. AI Gateway records the final status server-side, so you can use the generation ID to look up the results later.

#### generateText

```typescript
import { gateway, generateText } from 'ai';

const result = await generateText({
  model: 'anthropic/claude-opus-5',
  prompt: 'Explain quantum entanglement briefly',
});

const generationId = result.providerMetadata?.gateway?.generationId;
if (typeof generationId !== 'string') throw new Error('Missing generation ID');
const generation = await gateway.getGenerationInfo({ id: generationId });

console.log(`Model: ${generation.model}`);
console.log(`Cost: $${generation.totalCost.toFixed(6)}`);
console.log(`Latency: ${generation.latency}ms`);
console.log(`Prompt tokens: ${generation.promptTokens}`);
console.log(`Completion tokens: ${generation.completionTokens}`);
```

#### streamText

```typescript
import { gateway, streamText } from 'ai';

const result = streamText({
  model: 'anthropic/claude-opus-5',
  prompt: 'Explain quantum entanglement briefly',
});

let generationId: string | undefined;

for await (const part of result.stream) {
  if (
    !generationId &&
    'providerMetadata' in part &&
    typeof part.providerMetadata?.gateway?.generationId === 'string'
  ) {
    generationId = part.providerMetadata.gateway.generationId;
  }
}

if (generationId) {
  const generation = await gateway.getGenerationInfo({ id: generationId });
  console.log(`Cost: $${generation.totalCost.toFixed(6)}`);
  console.log(`Finish reason: ${generation.finishReason}`);
}
```

See the [AI SDK docs on generation lookup](https://ai-sdk.dev/providers/ai-sdk-providers/ai-gateway#generation-lookup) for the full list of response fields.

## REST API usage examples

### Group by day

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&date_part=day" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Group by model per hour

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&date_part=hour&group_by=model" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Group by user

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&group_by=user" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Group by tag

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&group_by=tag" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Group by credential type

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&group_by=credential_type" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Filter by the current API key

When you authenticate the report with an AI Gateway API key, use `self` to return only spend attributed to that key:

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&api_key_id=self" \
  -H "Authorization: Bearer $AI_GATEWAY_API_KEY"
```

### Filter by user, model, or tags

You can combine filters to narrow results:

```bash
curl "https://ai-gateway.vercel.sh/v1/report?start_date=2026-01-01&end_date=2026-01-31&date_part=day&user_id=user_123&model=anthropic/claude-sonnet-5&tags=production,api" \
  -H "Authorization: Bearer YOUR_API_KEY"
```


---

[View full sitemap](/docs/sitemap)
