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

# Get Consumption

> Query credit or ACU consumption analytics with flexible filtering, grouping, and pagination.

<Note>
  This is a **v2 endpoint** that uses Bearer token authentication and query parameters, unlike the v1 Analytics API which uses service keys in the request body. See [Authentication](#authentication) below.
</Note>

<Warning>
  This endpoint is **not** intended for real-time usage monitoring. Data is hourly-aggregated and the
  rate limit is low (10 requests per hour per team). Use it for periodic reporting and bulk export.
</Warning>

## Authentication

This endpoint uses **Bearer token** authentication. Include your service key in the `Authorization` header:

```
Authorization: Bearer <your_service_key>
```

The service key must have the **Analytics Read** permission. Create one in your [team settings](https://windsurf.com/team/settings) under "Service Keys".

## Billing Strategy

The response shape depends on your team's billing strategy:

| Strategy  | Populated fields                 | Description                         |
| --------- | -------------------------------- | ----------------------------------- |
| `CREDITS` | `prompt_credits`, `flex_credits` | Standard Enterprise SaaS teams      |
| `ACU`     | `billed_acus`                    | Teams billed by Agent Compute Units |

The `message_count` field (inside `consumption`) is always populated regardless of billing strategy.

## Grouping and Granularity

Use `granularity` and `group_by` to control the shape of returned data:

* **No granularity or grouping** — returns a single aggregated row for the entire date range
* **`granularity=daily`** — each row includes a `timestamp` in `YYYY-MM-DD` format
* **`granularity=monthly`** — each row includes a `timestamp` in `YYYY-MM` format
* **`group_by=user`** — each row includes a `user_id` and `user_email`
* **`group_by=user,model_uid`** — each row includes `user_id`, `user_email`, and `model_uid`
* **`group_by=ide`** — each row includes an `ide`

## Pagination

Results are paginated with a default page size of 1,000 rows (max 10,000). When more results are available,
the response includes a `next_page_cursor` in the `pagination` object. Pass it as the `page_cursor` query
parameter to fetch the next page.

Page cursors expire after 24 hours. A follow-up page request does not count as a new query against your rate limit.

## Caching

Responses include an `ETag` header. To avoid redundant data transfer, include the `If-None-Match` header
with the previous `ETag` value — the server will return `304 Not Modified` if the data has not changed.

## Rate Limits

This endpoint is rate-limited to **10 requests per hour** per team. If you exceed this limit, the
server returns `429 Too Many Requests` with a `Retry-After` header.

Paginating an earlier query (following a `next_page_cursor`) does **not** count against this limit —
only the initial query for each report does. The low limit reflects that this endpoint is for
periodic reporting, not real-time usage monitoring.


## OpenAPI

````yaml desktop/accounts/api-reference/analytics-v2-openapi.yaml GET /api/v2alpha/analytics/consumption
openapi: 3.1.0
info:
  title: Devin Desktop Analytics API v2
  version: 2.0.0
  description: >
    The Analytics API v2 provides credit and ACU consumption analytics for
    enterprise teams.

    Data is sourced from hourly-aggregated billing events and supports flexible
    filtering, grouping,

    and cursor-based pagination.
servers:
  - url: https://server.codeium.com
security:
  - bearerAuth: []
paths:
  /api/v2alpha/analytics/consumption:
    get:
      summary: Get consumption analytics
      description: >
        Query credit or ACU consumption data for the authenticated team. Results
        are sourced from

        hourly-aggregated billing events and can be filtered by date range,
        product, model, and group.


        The response shape depends on the team's billing strategy:

        - **Credits-based** teams receive `prompt_credits` and `flex_credits` in
        each row.

        - **ACU-based** teams receive `billed_acus` in each row.


        Responses are cached for 1 hour. Use `If-None-Match` with a previously
        returned `ETag` to

        receive a `304 Not Modified` when the data has not changed.


        These endpoints are designed for periodic reporting and bulk export.
        They are **not** intended for real-time usage monitoring: data is
        hourly-aggregated and the rate limit is low (10 requests per hour per
        team).
      operationId: getConsumption
      parameters:
        - name: start_date
          in: query
          required: true
          schema:
            type: string
            format: date
          description: Start of the date range (inclusive) in `YYYY-MM-DD` format.
          example: '2026-01-01'
        - name: end_date
          in: query
          required: true
          schema:
            type: string
            format: date
          description: >-
            End of the date range (inclusive) in `YYYY-MM-DD` format. The range
            must not exceed 90 days.
          example: '2026-01-31'
        - name: product
          in: query
          required: true
          schema:
            type: string
            enum:
              - agent
          description: Product to query consumption for.
          example: agent
        - name: granularity
          in: query
          required: false
          schema:
            type: string
            enum:
              - daily
              - monthly
          description: >
            Time granularity for grouping results. When specified, each row
            includes a `timestamp` field.

            If omitted, results are aggregated across the entire date range.
        - name: group_by
          in: query
          required: false
          schema:
            type: string
          description: >
            Comma-separated list of dimensions to group results by. Supported
            dimensions:

            - `user` — includes `user_id` and `user_email` in each row

            - `model_uid` — includes `model_uid` in each row

            - `ide` — includes `ide` in each row
          example: user,model_uid
        - name: models
          in: query
          required: false
          schema:
            type: string
          description: Comma-separated list of model UIDs to filter results to.
          example: claude-4-sonnet,gpt-4.1
        - name: group_id
          in: query
          required: false
          schema:
            type: string
          description: >-
            Filter results to users in a specific group. The service key must
            have access to this group.
        - name: user_id
          in: query
          required: false
          schema:
            type: string
          description: Filter results to a specific user (auth UID).
        - name: page_size
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 10000
            default: 1000
          description: Maximum number of rows to return per page.
        - name: page_cursor
          in: query
          required: false
          schema:
            type: string
          description: >-
            Opaque cursor from a previous response's
            `pagination.next_page_cursor` to fetch the next page.
        - name: If-None-Match
          in: header
          required: false
          schema:
            type: string
          description: >-
            ETag value from a previous response. If the data has not changed,
            the server returns `304 Not Modified`.
      responses:
        '200':
          description: Consumption data returned successfully.
          headers:
            ETag:
              schema:
                type: string
              description: >-
                Entity tag for cache validation. Pass this as `If-None-Match` in
                subsequent requests.
            Cache-Control:
              schema:
                type: string
              description: Cache directive (e.g., `private, max-age=3600`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConsumptionResponse'
              examples:
                credits:
                  summary: Credits-based team with daily granularity
                  value:
                    data:
                      - timestamp: '2026-01-15'
                        user_id: user_abc123
                        user_email: alice@example.com
                        consumption:
                          prompt_credits: 1250
                          flex_credits: 340
                          message_count: 87
                      - timestamp: '2026-01-15'
                        user_id: user_def456
                        user_email: bob@example.com
                        consumption:
                          prompt_credits: 980
                          flex_credits: 150
                          message_count: 52
                    pagination:
                      next_page_cursor: null
                    metadata:
                      billing_strategy: CREDITS
                      data_freshness: '2026-01-16T03:00:00Z'
                      query_time_ms: 1423
                      team_id: team_abc123
                acu:
                  summary: ACU-based team
                  value:
                    data:
                      - consumption:
                          billed_acus: 42.75
                          message_count: 310
                    pagination:
                      next_page_cursor: null
                    metadata:
                      billing_strategy: ACU
                      data_freshness: '2026-01-16T03:00:00Z'
                      query_time_ms: 892
                      team_id: team_def456
        '304':
          description: Data has not changed since the ETag provided in `If-None-Match`.
        '400':
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_param:
                  value:
                    error: start_date is required
                date_range:
                  value:
                    error: date range must not exceed 90 days
                bad_product:
                  value:
                    error: 'unsupported product: foo (supported: agent)'
        '401':
          description: Authentication failed or insufficient permissions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_auth:
                  value:
                    error: missing Authorization header
                invalid_key:
                  value:
                    error: invalid service key
                insufficient_permissions:
                  value:
                    error: insufficient permissions
        '403':
          description: >-
            The supplied page cursor does not belong to the authenticated team
            or requested group.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                cursor_team_mismatch:
                  value:
                    error: page cursor does not belong to this team
        '405':
          description: HTTP method not allowed (only `GET` is supported).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: >-
            Rate limit exceeded (10 requests per hour per team). Paginating an
            earlier query does not count against this limit.
          headers:
            Retry-After:
              schema:
                type: string
              description: Suggested wait time before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                rate_limited:
                  value:
                    error: rate limit exceeded
        '503':
          description: >-
            Analytics service is not available (e.g., in self-hosted
            deployments).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    ConsumptionResponse:
      type: object
      required:
        - data
        - pagination
        - metadata
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ConsumptionRow'
          description: Array of consumption data rows.
        pagination:
          type: object
          properties:
            next_page_cursor:
              type:
                - string
                - 'null'
              description: >
                Opaque cursor for fetching the next page of results. Pass this
                value as the `page_cursor`

                query parameter in a follow-up request. `null` when there are no
                more pages.

                Page cursors expire after 24 hours.
        metadata:
          type: object
          properties:
            billing_strategy:
              type: string
              enum:
                - CREDITS
                - ACU
              description: >
                The billing strategy for the authenticated team. Determines
                which fields in `consumption` are populated:

                - `CREDITS` — `prompt_credits` and `flex_credits`

                - `ACU` — `billed_acus`
            data_freshness:
              type: string
              format: date-time
              description: >-
                Timestamp indicating when the underlying data was last refreshed
                (truncated to the hour).
            query_time_ms:
              type: integer
              format: int64
              description: Server-side query execution time in milliseconds.
            team_id:
              type: string
              description: The team ID resolved from the authenticated service key.
            group_id:
              type: string
              description: >-
                The group ID the results were scoped to. Only present when
                `group_id` was supplied.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
    ConsumptionRow:
      type: object
      required:
        - consumption
      properties:
        timestamp:
          type: string
          description: >
            Time bucket for the row. Format depends on `granularity`:
            `YYYY-MM-DD` for daily, `YYYY-MM` for monthly.

            Only present when `granularity` is specified.
          examples:
            - '2026-05-01'
            - 2026-05
        user_id:
          type: string
          description: >-
            User identifier (auth UID). Only present when `group_by` includes
            `user`.
        user_email:
          type: string
          description: User's email address. Only present when `group_by` includes `user`.
          examples:
            - alice@example.com
        model_uid:
          type: string
          description: Model identifier. Only present when `group_by` includes `model_uid`.
          examples:
            - claude-4-sonnet
        ide:
          type: string
          description: IDE name. Only present when `group_by` includes `ide`.
          examples:
            - windsurf
            - jetbrains
        consumption:
          $ref: '#/components/schemas/Consumption'
    Consumption:
      type: object
      description: >-
        Usage metrics for the row. Fields are populated based on the team's
        billing strategy.
      properties:
        prompt_credits:
          type: integer
          format: int64
          description: Prompt credits consumed (credits-based billing only).
        flex_credits:
          type: integer
          format: int64
          description: Flex credits consumed (credits-based billing only).
        billed_acus:
          type: number
          format: double
          description: Billed ACUs consumed (ACU-based billing only).
        message_count:
          type: integer
          format: int64
          description: >-
            Number of messages (billing events) in this row. Always populated
            regardless of billing strategy.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        A service key with **Analytics Read** permission, passed as a Bearer
        token in the `Authorization` header.


        Create a service key in your [team
        settings](https://windsurf.com/team/settings) under the "Service Keys"
        section.

````