# Usage per end customer

> Requests, tokens and estimated provider cost for each of your own customers, by day or month, project and model — to bill them from in your own billing system.

Source: https://infro.io/docs/org/end-customer-usage

> **Note:** INFRO is in private early access. Running these examples requires an early-access account, an active trial or subscription entitlement, and your own provider connection. Self-serve purchasing is not generally open. See [Early access](https://infro.io/early-access).

If you charge your own users (your **end customers**) for the AI features in your product, you need to know what each of them used. INFRO already attributes every request to the end customer your app names in `metadata.user_id` (or the `X-INFRO-User-Id` header). This export gives you that usage as rows you can load into your billing system: one row per end customer, period, project and model.

> **Note:** **INFRO measures; you bill.** The export carries counts, tokens and the estimated cost your own provider will bill you for each row. What you charge your customers, and how, is decided in your billing system at your prices. INFRO never charges your end customers and takes no part in that billing.

Included from the **Team** plan. The per-customer cost view on the console's End customers screen is on every plan.

## From the console

On **Budgets → End customers**, choose **Usage for billing**, pick a month and whether you want one row per month or per day, and download the CSV. Leave the end customer empty for all of them, or type one id exactly as your app sends it.

## From the API

A billing job should read the same rows from the API with a gateway key whose observability access is **organization-wide** or limited to **one project** (a project key reads its project). A key limited to its own requests or to one environment is refused with `403 organization_scope_required`, because usage per end customer is kept per organization and project.

```bash
curl "https://api.infro.io/v1/usage/end-customers?period=2026-09&granularity=month" \
  -H "Authorization: Bearer $INFRO_API_KEY"
```

| Parameter | Values | Meaning |
| --- | --- | --- |
| `period` | `YYYY-MM` | One calendar month (UTC). Or send `from` and `to` instead. |
| `from`, `to` | `YYYY-MM-DD` | UTC dates; `from` is included, `to` is not. At most 93 days per call, and no earlier than 400 days ago. With neither `period` nor `from`/`to`: this month so far. |
| `granularity` | `day` (default), `month` | One row per UTC day, or per calendar month. |
| `end_user_id` | your id | One end customer, matched exactly. |
| `format` | `json` (default), `csv` | JSON pages; CSV is one file. |
| `limit` | 1 to 10,000 (default 1,000) | JSON rows per page. |
| `starting_after` | a `next_cursor` | The next JSON page. Rows are ordered by period, end customer, project and model. |

```json
{
  "object": "list",
  "window": { "from": "2026-09-01", "to": "2026-10-01" },
  "granularity": "month",
  "currency": "usd",
  "estimate": true,
  "data": [
    {
      "object": "end_customer_usage",
      "period_start": "2026-09-01",
      "end_user_id": "acme-corp",
      "project_id": "proj_7K2M…",
      "project_name": "Support assistant",
      "model": "anthropic/claude-sonnet-5",
      "requests": 1840,
      "unpriced_requests": 0,
      "cached_responses": 112,
      "failed_requests": 6,
      "prompt_tokens": 2210450,
      "completion_tokens": 388120,
      "cached_prompt_tokens": 905000,
      "units": 0,
      "estimated_provider_cost": "12.874310"
    }
  ],
  "has_more": true,
  "next_cursor": "WyIyMDI2LTA5LTAxIiwi…"
}
```

`format=csv` returns the same columns in the same order, with `estimated_provider_cost_usd` for the cost. A file over 200,000 rows is refused with `400 export_too_large` rather than cut short; ask for monthly rows, a shorter window or one end customer, or page through the JSON form. The response carries `X-INFRO-Export-Rows`, `X-INFRO-Window-Start`, `X-INFRO-Window-End` and `X-INFRO-Export-Schema-Version` (today `1`; a column is only ever added at the end without changing it).

## What each column counts

| Column | Counts |
| --- | --- |
| `requests` | Successful requests (HTTP status below 400) — the same definition as your plan's request allowance. |
| `unpriced_requests` | Of those, requests INFRO has no price for. They add nothing to the cost; they are never counted as $0. |
| `cached_responses` | Of those, requests answered from INFRO's response cache, with no provider call (a known $0). |
| `failed_requests` | Requests that returned an error. Usually nobody bills them; they are here so the file reconciles with your request log. |
| `prompt_tokens`, `completion_tokens`, `cached_prompt_tokens` | Token counts as the provider reported them, summed over every request in the row. |
| `units` | Images, seconds of audio or video, and characters for speech — the modality's own count. |
| `estimated_provider_cost` | What your own provider is estimated to bill you for the row, in USD, as a decimal string. Empty (`null`) when no successful request in the row was priced. |

**Cost is an estimate**, at the rate in force when each request ran — your own rates where you have set them, otherwise the vendor's list rate. Provider cost APIs report organization totals only, so a per-customer figure cannot be reconciled against your provider's bill. Counts and tokens are what the gateway recorded. Days are UTC. Requests without an end-customer id are not in this export; they are in [Analytics](https://infro.io/docs/observability/analytics) and the request log.

Each export is written to your organization's audit log (who, which window, which format).
