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

# Get Agent Output (Lines of Code)

> Query lines of code inserted and deleted by the agent and accepted by your team in Devin Desktop and the Devin CLI, with 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 token in the `Authorization` header:

```
Authorization: Bearer <your_token>
```

Use either a Devin service user API key with the **Use Local Analytics API** permission or a Windsurf
service key with the **Analytics Read** permission. See
[Authentication](/desktop/accounts/api-reference/analytics-v2-introduction#authentication) for how to
create each one.

## Metrics

The `metric` query parameter is required and takes a comma-separated list of the metrics to return.
Each requested metric appears as an integer field on every row:

| Metric | Description |
| - | - |
| `loc_inserted` | Lines inserted by the agent that the user accepted |
| `loc_deleted` | Lines deleted by the agent that the user accepted |

For example, `?metric=loc_inserted,loc_deleted` returns both; `?metric=loc_inserted` returns only
`loc_inserted`. Requests without `metric`, or naming an unknown metric, fail with `400`.

Lines are counted when a user accepts an agent edit in [Devin Desktop](/desktop/introducing-devin-desktop) or the
[Devin CLI](/cli), from any model. The `product` parameter is also required and currently accepts only
`agent`.

## 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=session`** — each row includes a `session_id` (the Devin Desktop conversation or CLI session the lines were accepted in)
* **`group_by=model_uid`** — each row includes a `model_uid`
* **`group_by=ide`** — each row includes an `ide`
* **`group_by=ide,ide_version`** — each row includes `ide` and `ide_version` (grouping by `ide_version` requires `ide` to also be included)
* **`group_by=os`** — each row includes an `os`, such as `darwin` (macOS), `windows`, or `linux`
* **`group_by=source`** — each row includes a `source`: `CASCADE_CLIENT` for lines accepted in Devin Desktop, `CHISEL` for lines accepted in the Devin CLI (including the CLI running as an agent inside other editors)

Dimensions can be combined, for example `group_by=user,source,model_uid`. The same `models`,
`group_id`, and `user_id` filters as [Get Consumption](/desktop/accounts/api-reference/get-consumption)
apply.

## 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, with the same `metric` list as the original request. Cursors are bound
to the endpoint and metrics that issued them; a cursor from `/consumption`, or one issued for a different
`metric` list, is rejected with `400`.

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

## 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/output
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, active-user, and
    agent output

    (accepted lines of code) analytics for enterprise teams. Data is sourced
    from hourly aggregates

    and supports flexible filtering, grouping, and cursor-based pagination.
servers:
  - url: https://server.codeium.com
security:
  - bearerAuth: []
paths:
  /api/v2alpha/analytics/output:
    get:
      summary: Get agent output analytics (lines of code)
      description: >
        Query agent output for the authenticated team. The required `metric`
        parameter is a

        comma-separated list of the metrics to return: `loc_inserted` and/or
        `loc_deleted`, lines

        inserted or deleted by the agent and accepted by users in Devin Desktop
        and the Devin CLI.

        Each requested metric appears as an integer field on every row. Results
        are sourced from hourly

        aggregates and can be filtered by date range, product, model, group, and
        user, and grouped

        by the same dimensions as consumption plus `session` and `source` (Devin
        Desktop vs. CLI).


        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: getOutput
      parameters:
        - name: metric
          in: query
          required: true
          schema:
            type: string
          description: >
            Comma-separated list of output metrics to return; each appears as a
            field on every row. Supported metrics:

            - `loc_inserted` — lines inserted by the agent that the user
            accepted

            - `loc_deleted` — lines deleted by the agent that the user accepted
          example: loc_inserted,loc_deleted
        - 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-06-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-06-30'
        - name: product
          in: query
          required: true
          schema:
            type: string
            enum:
              - agent
          description: Product to query output 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

            - `session` — includes `session_id` in each row

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

            - `ide` — includes `ide` in each row

            - `ide_version` — includes `ide_version` in each row; requires `ide`
            to also be included

            - `os` — includes `os` in each row

            - `source` — includes `source` in each row (`CASCADE_CLIENT` for
            Devin Desktop, `CHISEL` for the Devin CLI)
          example: source,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. Not supported with Devin service user API
            keys.
        - 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. Pass the same
            `metric` list as the request that issued it; cursors issued by other
            endpoints or for a different `metric` list are rejected.
      responses:
        '200':
          description: Output data returned successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OutputResponse'
              examples:
                by_source:
                  summary: Daily lines of code by client
                  value:
                    data:
                      - timestamp: '2026-06-15'
                        source: CASCADE_CLIENT
                        loc_inserted: 18420
                        loc_deleted: 3105
                      - timestamp: '2026-06-15'
                        source: CHISEL
                        loc_inserted: 92310
                        loc_deleted: 11874
                    pagination:
                      next_page_cursor: null
                    metadata:
                      data_freshness: '2026-06-16T03:00:00Z'
                      query_time_ms: 1311
                      team_id: team_abc123
                by_user_model:
                  summary: metric=loc_inserted grouped by user and model
                  value:
                    data:
                      - user_id: user_abc123
                        user_email: alice@example.com
                        model_uid: claude-4-sonnet
                        loc_inserted: 4210
                    pagination:
                      next_page_cursor: null
                    metadata:
                      data_freshness: '2026-06-16T03:00:00Z'
                      query_time_ms: 980
                      team_id: team_abc123
        '400':
          description: Invalid request parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing_metric:
                  value:
                    error: metric is required
                bad_metric:
                  value:
                    error: >-
                      unsupported metric: acus (supported: loc_inserted,
                      loc_deleted)
                missing_product:
                  value:
                    error: product is required
                bad_group_by:
                  value:
                    error: 'unsupported group_by dimension for output: foobar'
        '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:
    OutputResponse:
      type: object
      required:
        - data
        - pagination
        - metadata
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/OutputRow'
          description: Array of output 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:
            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.
    OutputRow:
      type: object
      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
        session_id:
          type: string
          description: >-
            Devin Desktop conversation or Devin CLI session identifier. Only
            present when `group_by` includes `session`.
        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
            - devin-cli
        ide_version:
          type: string
          description: >-
            IDE version. Only present when `group_by` includes `ide_version`
            (which additionally requires `ide`).
          examples:
            - 1.0.0
        os:
          type: string
          description: >-
            Operating system the request came from. Only present when `group_by`
            includes `os`.
          examples:
            - darwin
            - windows
            - linux
        source:
          type: string
          enum:
            - CASCADE_CLIENT
            - CHISEL
          description: >
            Client the lines were accepted in: `CASCADE_CLIENT` for Devin
            Desktop, `CHISEL` for the Devin CLI

            (including the CLI running as an agent inside other editors). Only
            present when `group_by` includes `source`.
        loc_inserted:
          type: integer
          format: int64
          description: >-
            Lines inserted by the agent that the user accepted. Only present
            when `metric` includes `loc_inserted`.
        loc_deleted:
          type: integer
          format: int64
          description: >-
            Lines deleted by the agent that the user accepted. Only present when
            `metric` includes `loc_deleted`.
  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.

````

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