# Query a usage report

`POST https://api.endless.app/reports/query`

Source: https://endless.app/docs/api/reports/query

Query a usage report.

## Authentication

- `bearerAuth`: HTTP bearer (JWT)

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Endless-Api-Version` | header | string | no | Pin the caller to an API major (`1`). Omit to accept the current version. A major this deployment cannot serve is refused with 400 `unsupported_api_version`. |

## Request body

Required.

Content type: `application/json` — object

- `organization_ids` ("all" | array<string>, required): The organizations the report covers. The caller must reach every one; `all` is staff-only.
- `metrics` (array<"credits_spent" | "credits_granted" | "runs" | "failed_runs" | "failed_runs_charged" | "completed_runs_uncharged" | "chats" | "messages" | "assets" | "active_members" | "inactive_members" | "tool_calls" | "mcp_tool_calls" | "research_calls">, required): The first metric orders a ranking and a breakdown.
- `group_by` ("none" | "day" | "week" | "month" | "user" | "workspace" | "team" | "feature" | "model" | "output_type" | "status" | "provider" | "source" | "credit_type" | "channel")
- `period` (object, required)
- `timezone` (string): Day, week and month buckets and the period edges use this zone.
- `filters` (object)
  - `user_ids` (array<string>)
  - `team_ids` (array<string (uuid)>): The team each charge was made under.
  - `categories` (object): Keep only facts whose category is one of these values: the keys a breakdown returns, e.g. a model's codename or a feature.
    - `feature` (array<string>)
    - `model` (array<string>)
    - `output_type` (array<string>)
    - `status` (array<string>)
    - `provider` (array<string>)
    - `source` (array<string>)
    - `credit_type` (array<string>)
    - `channel` (array<string>)
- `limit` (integer): Rows in a ranking or a breakdown.

## Responses

### 200 OK

Content type: `application/json` — object

- `audience` ("all" | array<object>, required): Whose usage the report counted: each workspace by id, name and slug. `user_ids: null` = every member of that workspace; a list = only those people.
  - `organization_id` (string, required)
  - `name` (string, required)
  - `slug` (string, required)
  - `user_ids` (array<string> | null, required)
- `period` (object, required)
  - `from` (string (date-time), required)
  - `to` (string (date-time), required)
  - `timezone` (string, required)
  - `earlier_cycle` (boolean): Billing cycle periods only: whether a cycle before this one exists, so `offset - 1` can be asked.
- `result` (object, required)

### Errors

- `400` (Error): The request is malformed, or failed input validation. `message` names the field and the rule it broke; `data.issues` carries them individually.
- `401` (Error): No bearer token, or a token that failed verification.
- `402` (Error): The workspace has no credits left, or the caller is over a spending limit.
- `403` (Error): Authenticated, but the caller's role in this workspace does not carry the permission this operation needs.
- `409` (Error): The request is well-formed, but the resource's current state forbids it — a taken name, a last admin, a limit already reached.
- `429` (Error): The caller has spent its rate-limit window. `Retry-After` says when to come back.
- `500` (Error): The request failed on our side. Safe to retry an idempotent operation with backoff.
