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

# The analysis library

> Every analysis group in your workspace, with its items.

<Note>
  **Paged.** This list used to return every row in one response. It now returns 20 by default -
  pass `?limit=` up to 100, and `?cursor=` with the previous response's `next_cursor` for the
  next page. See [Pagination](/developers/api-reference#pagination).
</Note>

Post-call analysis extracts structured data from a conversation — a sentiment, an outcome, a lead
temperature, whatever you define.

Groups belong to the **workspace**, not to an agent: a group usually outlives any one agent, and
several agents run the same one. An agent stores only the selection, in `analysis_group_ids`.

**Default Analysis** is the platform's own group — Call Summary, User Sentiment, Outcome and
Language. Every new agent is created with it attached, which is why an agent produces a summary
without anyone configuring anything. Its four items cannot be renamed or reshaped; you can detach the
whole group from an agent, and add items of your own.


## OpenAPI

````yaml developers/openapi.json GET /v1/custom-analysis
openapi: 3.1.0
info:
  title: Vocily API
  description: >-
    Public REST API for Vocily. Build and configure an agent, publish a version
    and put it live, place outbound calls, and read back calls, chats and what
    the agent remembered. Authenticate with a workspace API key as a Bearer
    token.


    Some things stay in the dashboard, by design: creating an API key, buying or
    connecting a phone number, setting an agent's webhook URL, connecting
    WhatsApp and its templates, building HTTP tools, and running batch
    campaigns.
  version: v1
servers:
  - url: https://api.vocily.ai
    description: Production
security: []
paths:
  /v1/custom-analysis:
    get:
      tags:
        - custom-analysis
      summary: Get Custom Analysis Library
      description: >-
        Every analysis group in this workspace, with the values inside it,
        **cursor-paginated**.


        In creation order — oldest first — which is what `sort_order` leaving
        the public contract

        left behind. The envelope is `data`, like every other list; it was
        `{"groups": […]}` for one

        release and `{"categories": […]}` before that.
      operationId: get_custom_analysis_library_v1_custom_analysis_get
      parameters:
        - name: cursor
          in: query
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              Opaque cursor from a previous response's `next_cursor`; omit for
              the first page
            title: Cursor
          description: >-
            Opaque cursor from a previous response's `next_cursor`; omit for the
            first page
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            maximum: 100
            minimum: 1
            default: 20
            title: Limit
          description: Maximum records to return in one page.
      responses:
        '200':
          description: >-
            The workspace's analysis library, in creation order. Groups are
            workspace-level — an agent stores only the selection, in
            `analysis_group_ids`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        description:
                          type: string
                          nullable: true
                        model:
                          type: string
                          nullable: true
                        temperature:
                          type: number
                          nullable: true
                        max_tokens:
                          type: integer
                          nullable: true
                        conditions:
                          type: object
                        is_default:
                          type: boolean
                        items:
                          type: array
                          items:
                            type: object
                            properties:
                              id:
                                type: string
                              category_id:
                                type: string
                              name:
                                type: string
                              description:
                                type: string
                              result_format:
                                type: string
                                enum:
                                  - string
                                  - number
                                  - integer
                                  - boolean
                                  - array
                                  - object
                              extraction_method:
                                type: string
                                enum:
                                  - ai
                                  - regex
                              required:
                                type: boolean
                              constraints:
                                type: object
                              fields:
                                type: array
                                items:
                                  type: object
                              enabled:
                                type: boolean
                              is_system:
                                type: boolean
                              created_at:
                                type: string
                                format: date-time
                              updated_at:
                                type: string
                                format: date-time
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                    description: The rows on this page.
                  has_more:
                    type: boolean
                    description: Whether another page exists. `false` on the last.
                  next_cursor:
                    type: string
                    nullable: true
                    description: >-
                      Pass back as `?cursor=` for the next page; `null` on the
                      last one. **Opaque** — do not parse or construct one. A
                      cursor from a differently sorted list is refused with
                      `invalid_cursor` rather than silently returning page 1.
                required:
                  - data
                  - has_more
              example:
                data:
                  - name: Default Analysis
                    description: >-
                      Vocily's built-in post-call analysis. Attached to every
                      new agent; detach it from an agent that does not need it.
                      You can reword any extraction description, switch a value
                      off, or add your own values to this group.
                    model: null
                    temperature: null
                    max_tokens: null
                    conditions:
                      min_messages: 4
                    id: 00000007-0000-4000-8000-000000000007
                    items:
                      - name: Call Summary
                        description: >-
                          Write a short recap of this conversation in English —
                          one to three sentences — even when the conversation
                          happened in Hindi, Hinglish, or any other language.
                          Cover what the caller wanted, what the agent did about
                          it, and how the call ended. Report only what was
                          actually said; do not speculate about intent that was
                          never expressed.
                        extraction_method: ai
                        result_format: string
                        required: false
                        constraints: {}
                        fields: []
                        enabled: true
                        id: 0000000c-0000-4000-8000-00000000000c
                        category_id: 00000007-0000-4000-8000-000000000007
                        is_system: true
                        created_at: '2026-09-01T19:50:05.876753Z'
                        updated_at: '2026-09-01T19:50:05.876753Z'
                      - name: User Sentiment
                        description: >-
                          Score the caller's overall sentiment across the whole
                          conversation — the caller's, never the agent's.

                          - positive: the caller was satisfied, agreed, thanked
                          the agent, showed interest, or got what they called
                          for.

                          - negative: the caller was frustrated, annoyed,
                          complained, disputed something, repeatedly refused, or
                          hung up unhappy.

                          - neutral: the caller was matter-of-fact, or the
                          exchange was purely informational, or positive and
                          negative moments roughly balanced out.

                          When the caller's tone shifted during the call, judge
                          by where they ended up. When there is genuinely too
                          little to go on, answer neutral.
                        extraction_method: ai
                        result_format: string
                        required: false
                        constraints:
                          enum:
                            - positive
                            - neutral
                        fields: []
                        enabled: true
                        id: 0000000d-0000-4000-8000-00000000000d
                        category_id: 00000007-0000-4000-8000-000000000007
                        is_system: true
                        created_at: '2026-09-01T19:50:05.876753Z'
                        updated_at: '2026-09-01T19:50:05.876753Z'
                    is_default: true
                    created_at: '2026-09-01T19:50:05.876753Z'
                    updated_at: '2026-09-01T19:50:05.876753Z'
                  - name: dafa
                    description: asdasd
                    model: null
                    temperature: null
                    max_tokens: null
                    conditions: {}
                    id: 0000000e-0000-4000-8000-00000000000e
                    items: []
                    is_default: false
                    created_at: '2026-09-05T20:41:06.966532Z'
                    updated_at: '2026-09-05T20:41:06.966532Z'
                has_more: false
                next_cursor: null
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                detail: Invalid API key
                code: UNAUTHORIZED
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit exceeded — honor `Retry-After`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                code: rate_limited
      security:
        - bearerAuth: []
components:
  schemas:
    ApiError:
      type: object
      description: >-
        Error envelope. `code` is derived from the HTTP status, so branch on it
        for the CLASS of failure; the specific reason is `detail.code`. Every
        public refusal carries both.
      properties:
        detail:
          type: object
          description: >-
            The reason. `code` is the domain reason (e.g. `call_not_found`) and
            `message` is a sentence safe to log. On a `422` it also carries
            `errors[]`, one entry per rejected field — see
            `HTTPValidationError`.
          properties:
            code:
              type: string
              example: call_not_found
            message:
              type: string
              example: Call not found
          required:
            - code
            - message
        code:
          type: string
          description: Derived from the HTTP status, not the domain reason.
          example: NOT_FOUND
    HTTPValidationError:
      type: object
      title: HTTPValidationError
      description: >-
        A request the API could not read: a field of the wrong type, out of
        range, missing, or one we do not accept. Same envelope as every other
        error.
      properties:
        detail:
          type: object
          description: >-
            What was wrong, as `code`, a one-line `message`, and every offending
            field in `errors`.
          required:
            - code
            - message
            - errors
          properties:
            code:
              type: string
              enum:
                - validation_error
            message:
              type: string
              description: >-
                The first problem in one line, with a count of the rest — e.g.
                `model.temperature: Input should be less than or equal to 2 (and
                1 more)`.
            errors:
              type: array
              items:
                $ref: '#/components/schemas/ValidationError'
              description: >-
                One entry per offending field. **Every problem is reported at
                once**, not just the first, so a malformed body needs one round
                trip to fix rather than one per field.
        code:
          type: string
          enum:
            - VALIDATION_ERROR
          description: Derived from the HTTP status, as on every error.
    ValidationError:
      type: object
      title: ValidationError
      required:
        - field
        - message
        - type
      properties:
        field:
          type: string
          description: >-
            The offending field as a path from the root of your request —
            `voice.speed`, `variables[0].key`, or `query.limit` for a query
            parameter. **This is the field to read.**
        message:
          type: string
          description: What is wrong with it, in plain language.
        type:
          type: string
          description: >-
            A stable machine code for the kind of failure, e.g.
            `extra_forbidden` for a field we do not accept, `missing` for a
            required one, or `less_than_equal` for a number out of range. Switch
            on this rather than on `message`, which may be reworded.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Your API key as a Bearer token, e.g. `Authorization: Bearer vk_…`.'

````