> ## Documentation Index
> Fetch the complete documentation index at: https://docs.varg.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Spend breakdown

> Spend ranked by one or two dimensions. Rows plus `other` always add up to `total`. Returns 400 `too_many_groups` when the grouping yields more than 5000 groups.

All analytics endpoints return `{ "data": ..., "meta": ... }`. `meta` carries the resolved range
(`from` inclusive, `to` exclusive, ISO 8601 UTC), `timezone`, the comparison period, applied `filters`,
`data_as_of`, `money_unit`, `time_basis` and `attribution_scope`.

Amounts are whole credits; fields ending in `_cents` are credits (1 credit = 1 cent). Charges are counted
when they were posted to the ledger. On team accounts, non-members only see their own identity
dimensions (`attribution_scope: self`); others collapse into "Other ..." groups.

With `format=csv` every row is exported (no `other` roll-up).




## OpenAPI

````yaml /openapi.yaml get /analytics/breakdown
openapi: 3.1.0
info:
  title: varg API
  version: 2.0.0
  description: |
    Unified REST API for AI media generation at `api.varg.ai/v2`.

    One API key, ~80 models across 8 providers, async jobs, stable output URLs
    on `s3.varg.ai`, files with lineage, and transparent credit billing
    (1 credit = 1 cent = $0.01).

    **The async job pattern:** every generation request returns `202 Accepted`
    with a job object (`status: queued`). Poll `GET /jobs/{id}` until the job
    reaches a terminal status (`completed`, `failed`, or `cancelled`), then read
    `output.outputs[0].url`. Alternatively, set `options.webhook_url` in the
    request to receive an HMAC-signed callback when the job finishes.
servers:
  - url: https://api.varg.ai/v2
security:
  - bearerAuth: []
tags:
  - name: Generation
    description: >-
      Create generation jobs (image, video, speech, music, transcription,
      ffmpeg, render, pipeline)
  - name: Tools
    description: Discover tools, their schemas, and call any tool generically
  - name: Jobs
    description: Poll and manage job lifecycle
  - name: Files
    description: Upload, import, probe, and manage files
  - name: Folders
    description: Group files into folders and file generated output automatically
  - name: Lineage
    description: Resolve which job produced a file
  - name: Presets
    description: Browse and apply reusable parameter values — voices, styles
  - name: Templates
    description: Browse, publish, use and render community templates
  - name: Pricing
    description: Estimate costs and browse the price catalog
  - name: Billing
    description: Balance, usage, and transaction history
  - name: Analytics
    description: >-
      Spend, runs and files over time — summaries, time series, breakdowns,
      activity
  - name: Account
    description: Identity and API key management
paths:
  /analytics/breakdown:
    get:
      tags:
        - Analytics
      summary: Spend breakdown
      description: >
        Spend ranked by one or two dimensions. Rows plus `other` always add up
        to `total`. Returns 400 `too_many_groups` when the grouping yields more
        than 5000 groups.


        All analytics endpoints return `{ "data": ..., "meta": ... }`. `meta`
        carries the resolved range

        (`from` inclusive, `to` exclusive, ISO 8601 UTC), `timezone`, the
        comparison period, applied `filters`,

        `data_as_of`, `money_unit`, `time_basis` and `attribution_scope`.


        Amounts are whole credits; fields ending in `_cents` are credits (1
        credit = 1 cent). Charges are counted

        when they were posted to the ledger. On team accounts, non-members only
        see their own identity

        dimensions (`attribution_scope: self`); others collapse into "Other ..."
        groups.


        With `format=csv` every row is exported (no `other` roll-up).
      operationId: getAnalyticsBreakdown
      parameters:
        - $ref: '#/components/parameters/AnalyticsFrom'
        - $ref: '#/components/parameters/AnalyticsTo'
        - $ref: '#/components/parameters/AnalyticsTimezone'
        - $ref: '#/components/parameters/AnalyticsCompare'
        - $ref: '#/components/parameters/AnalyticsCompareFrom'
        - $ref: '#/components/parameters/AnalyticsCompareTo'
        - $ref: '#/components/parameters/AnalyticsTool'
        - $ref: '#/components/parameters/AnalyticsModel'
        - $ref: '#/components/parameters/AnalyticsWorkspaceId'
        - $ref: '#/components/parameters/AnalyticsApiKeyId'
        - $ref: '#/components/parameters/AnalyticsMemberId'
        - $ref: '#/components/parameters/AnalyticsCreator'
        - $ref: '#/components/parameters/AnalyticsSource'
        - $ref: '#/components/parameters/AnalyticsStatus'
        - $ref: '#/components/parameters/AnalyticsBreakdownGroupBy'
        - $ref: '#/components/parameters/AnalyticsBreakdownSort'
        - $ref: '#/components/parameters/AnalyticsBreakdownLimit'
        - $ref: '#/components/parameters/AnalyticsFormat'
      responses:
        '200':
          description: Result envelope (JSON) or CSV export
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnalyticsBreakdownResponse'
            text/csv:
              schema:
                type: string
                description: >-
                  Same rows as the JSON response, flattened. Amounts are in
                  credits.
          headers:
            Content-Disposition:
              description: Attachment filename, `varg-spend-breakdown-<from>-<to>.csv`.
              schema:
                type: string
        '400':
          description: >-
            Invalid parameter (code `invalid_request`, `invalid_range`,
            `range_too_large`, `invalid_timezone`, `invalid_filter`,
            `unsupported_group_by`, ...)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '503':
          description: Analytics is temporarily unavailable (`analytics_unavailable`)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  parameters:
    AnalyticsFrom:
      name: from
      in: query
      required: false
      description: >
        Range start, inclusive. `YYYY-MM-DD` (local midnight in `timezone`), a
        local date-time

        (`2026-09-01T09:30`), or an ISO 8601 instant with offset. Default: `to`
        minus 30 days.

        Ranges are limited to 366 days.
      schema:
        type: string
        maxLength: 40
      example: '2026-09-01'
    AnalyticsTo:
      name: to
      in: query
      required: false
      description: Range end, exclusive. Same formats as `from`. Default is now.
      schema:
        type: string
        maxLength: 40
      example: '2026-10-01'
    AnalyticsTimezone:
      name: timezone
      in: query
      required: false
      description: >-
        IANA timezone used for date-only bounds and calendar buckets. Default
        `UTC`.
      schema:
        type: string
        maxLength: 64
      example: Europe/Berlin
    AnalyticsCompare:
      name: compare
      in: query
      required: false
      description: >
        `previous_period` compares against the equal-length period right before
        `from`;

        `none` disables comparison. Default is `previous_period` on
        `/analytics/summary`

        and `none` elsewhere. Ignored when `compare_from`/`compare_to` are
        given.
      schema:
        type: string
        enum:
          - previous_period
          - none
    AnalyticsCompareFrom:
      name: compare_from
      in: query
      required: false
      description: Explicit comparison start. Must be sent together with `compare_to`.
      schema:
        type: string
        maxLength: 40
    AnalyticsCompareTo:
      name: compare_to
      in: query
      required: false
      description: >-
        Explicit comparison end, exclusive. Must be sent together with
        `compare_from`.
      schema:
        type: string
        maxLength: 40
    AnalyticsTool:
      name: tool
      in: query
      required: false
      description: >-
        Filter by capability. Comma-separated tool keys (`video`, `image`,
        `speech`, `music`, `render`, `pipeline`, ...) or `none`. Up to 50
        values.
      schema:
        type: string
        maxLength: 4000
      example: video,image
    AnalyticsModel:
      name: model
      in: query
      required: false
      description: Filter by model. Comma-separated model ids or `none`. Up to 50 values.
      schema:
        type: string
        maxLength: 4000
    AnalyticsWorkspaceId:
      name: workspace_id
      in: query
      required: false
      description: >-
        Filter by folder. Comma-separated folder ids or `none` (no folder). Up
        to 50 values.
      schema:
        type: string
        maxLength: 4000
    AnalyticsApiKeyId:
      name: api_key_id
      in: query
      required: false
      description: >-
        Filter by the API key that started the run. Comma-separated key ids or
        `none`. Up to 50 values.
      schema:
        type: string
        maxLength: 4000
    AnalyticsMemberId:
      name: member_id
      in: query
      required: false
      description: >-
        Filter by the person who started the run. Comma-separated user ids or
        `none`. Up to 50 values.
      schema:
        type: string
        maxLength: 4000
    AnalyticsCreator:
      name: creator
      in: query
      required: false
      description: >
        Filter by creator: `api_key:<id>` (a personal API key) or `member:<id>`
        (a person),

        comma-separated, or `none`. Up to 50 values.
      schema:
        type: string
        maxLength: 4000
    AnalyticsSource:
      name: source
      in: query
      required: false
      description: >
        Filter by how the run was started. Comma-separated values of `app` (a
        person in the web app),

        `api` (API key, SDK, CLI), `mcp` (an agent via MCP), `internal` (varg
        system keys), `unknown`.
      schema:
        type: string
        maxLength: 4000
      example: api,mcp
    AnalyticsStatus:
      name: status
      in: query
      required: false
      description: >
        Filter by the charged job's status. Comma-separated values of
        `completed`, `failed`,

        `cancelled`, `awaiting_confirmation`, `running`, `submitting`, `queued`,
        `unknown`.
      schema:
        type: string
        maxLength: 4000
    AnalyticsBreakdownGroupBy:
      name: group_by
      in: query
      required: true
      description: >-
        One or two dimensions, comma-separated (for example `model` or
        `tool,source`).
      schema:
        type: string
        maxLength: 40
      example: model
    AnalyticsBreakdownSort:
      name: sort
      in: query
      required: false
      description: Ranking metric. Default `spend`.
      schema:
        type: string
        enum:
          - spend
          - charges
          - jobs
          - runs
        default: spend
    AnalyticsBreakdownLimit:
      name: limit
      in: query
      required: false
      description: >-
        Rows to return before the rest is rolled into `other`. 1-200, default
        20. Out-of-range values are clamped. Ignored for CSV, which exports
        every row.
      schema:
        type: integer
        minimum: 1
        maximum: 200
        default: 20
    AnalyticsFormat:
      name: format
      in: query
      required: false
      description: >
        `json` (default) returns the `{ data, meta }` envelope. `csv` returns
        the same rows as

        `text/csv` with a `Content-Disposition` attachment filename. Amounts are
        in credits.
      schema:
        type: string
        enum:
          - json
          - csv
  schemas:
    AnalyticsBreakdownResponse:
      type: object
      required:
        - data
        - meta
      properties:
        data:
          $ref: '#/components/schemas/AnalyticsBreakdown'
        meta:
          $ref: '#/components/schemas/AnalyticsMeta'
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              example: model_not_found
            message:
              type: string
              example: 'Unknown model: flux-shnell'
            details: {}
    AnalyticsBreakdown:
      type: object
      required:
        - group_by
        - sort
        - rows
        - other
        - total
      properties:
        group_by:
          type: array
          items:
            $ref: '#/components/schemas/AnalyticsDimension'
        sort:
          type: string
          enum:
            - spend
            - charges
            - jobs
            - runs
        rows:
          type: array
          items:
            $ref: '#/components/schemas/AnalyticsBreakdownRow'
        other:
          type:
            - object
            - 'null'
          description: Groups beyond `limit`, rolled up. Null when nothing was cut.
          properties:
            groups:
              type: integer
            spend_cents:
              type: integer
            share:
              type: number
            charges:
              type: integer
            jobs:
              type: integer
        total:
          type: object
          properties:
            spend_cents:
              type: integer
            charges:
              type: integer
            jobs:
              type: integer
            runs:
              type: integer
            groups:
              type: integer
    AnalyticsMeta:
      type: object
      description: Metadata describing how the numbers were computed.
      required:
        - definition_version
        - data_as_of
        - money_unit
        - time_basis
        - attribution_scope
      properties:
        definition_version:
          type: string
          description: Changes whenever a metric's meaning changes.
          example: '2026-09-28'
        from:
          type: string
          format: date-time
          description: Resolved range start (inclusive).
        to:
          type: string
          format: date-time
          description: Resolved range end (exclusive).
        timezone:
          type: string
          example: UTC
        compare:
          type:
            - object
            - 'null'
          description: The comparison period, or null when none.
          properties:
            from:
              type: string
              format: date-time
            to:
              type: string
              format: date-time
        filters:
          type: object
          description: Filters applied, keyed by query parameter name.
          additionalProperties:
            type: array
            items:
              type: string
        data_as_of:
          type: string
          format: date-time
        money_unit:
          type: string
          enum:
            - cent
          description: Amounts are whole credits, in fields ending in `_cents`.
        time_basis:
          type: string
          enum:
            - posted_at
            - lifetime
            - created_at
          description: >-
            `posted_at` = when the ledger charge was posted; `created_at` = when
            a file was made.
        attribution_scope:
          type: string
          enum:
            - full
            - self
          description: '`self` means identity dimensions show only the caller''s own values.'
    AnalyticsDimension:
      type: string
      enum:
        - tool
        - model
        - workspace
        - api_key
        - member
        - creator
        - source
        - status
      description: A dimension spend can be grouped or filtered by.
    AnalyticsBreakdownRow:
      type: object
      required:
        - group
        - labels
        - spend_cents
        - share
        - charges
        - jobs
        - runs
      properties:
        group:
          type: object
          description: Group key per requested dimension.
          additionalProperties:
            type: string
        labels:
          type: object
          description: Display label per requested dimension.
          additionalProperties:
            type: string
        details:
          type: object
          description: Extra facts per dimension (avatar, revoked key, deleted folder).
          additionalProperties:
            type: object
            additionalProperties: true
        spend_cents:
          type: integer
        share:
          type: number
          description: Fraction of total spend, 0-1.
        charges:
          type: integer
        jobs:
          type: integer
        runs:
          type: integer
        previous_spend_cents:
          type: integer
          description: Present only when a comparison period is set.
        change_pct:
          type:
            - number
            - 'null'
  responses:
    Unauthorized:
      description: Missing or invalid API key / JWT
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            unauthorized:
              value:
                error:
                  code: unauthorized
                  message: Invalid or missing API key or JWT
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        varg API key (`varg_...`). Get one at [app.varg.ai](https://app.varg.ai)
        or run `bunx vargai login`. App sessions may alternatively send a
        Supabase JWT.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.