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

# Validate a test spec

> Checks a spec as create (or, with `testId`, as an edit of that test) would, and stores and spends nothing. 200 whatever the result: `ok` says whether it would be stored. A read key may call it.



## OpenAPI

````yaml /api-reference/openapi.json post /v1/agents/{agentId}/tests/validate
openapi: 3.1.0
info:
  title: SignalMD API
  version: 1.0.0
  description: >-
    SignalMD reads a voice agent's production calls and says what to fix, then
    tests whether the fix worked.

    This API exposes the same data the web app shows: agents, calls and their
    traces, signals, issues,

    versions and their comparisons, tests, and test runs.


    Authenticate with `Authorization: Bearer sig_...` (an API key from the API
    keys page). Read keys may

    call every `read` operation; write keys may also call `write` operations,
    within their monthly budget.

    Each operation's scope is in `x-signal-scope`. Errors share one envelope
    (`Error`), lists share one

    cursor scheme (`limit`, `cursor`, `hasMore`, `nextCursor`), and every
    response carries `Request-Id`

    and `RateLimit-*` headers.
servers:
  - url: https://api.signalmd.dev
    description: Production
  - url: http://localhost:43124
    description: Local development
security:
  - bearerAuth: []
tags:
  - name: Account
    description: Who the token belongs to and what it may do.
  - name: Agents
    description: Voice agents connected to the workspace.
  - name: Calls
    description: Production calls, their traces and per-call signals.
  - name: Signals
    description: What SignalMD noticed across calls.
  - name: Issues
    description: 'Problems worth fixing: where, why, and what to change.'
  - name: Versions
    description: Agent versions and how each one did.
  - name: Comparisons
    description: Stored comparisons between two versions.
  - name: Tests
    description: Tests, test sets, personas and coverage.
  - name: Runs
    description: Test runs and the attempts inside them.
paths:
  /v1/agents/{agentId}/tests/validate:
    post:
      tags:
        - Tests
      summary: Validate a test spec
      description: >-
        Checks a spec as create (or, with `testId`, as an edit of that test)
        would, and stores and spends nothing. 200 whatever the result: `ok` says
        whether it would be stored. A read key may call it.
      operationId: validateTest
      parameters:
        - schema:
            type: string
            format: uuid
            pattern: >-
              ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
            example: 3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f
            description: The agent's id.
          required: true
          description: The agent's id.
          name: agentId
          in: path
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidateTestRequest'
      responses:
        '200':
          description: Problems, and the spec as it would be stored.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SpecValidation'
        '400':
          description: 'Invalid request: a parameter or the body failed validation.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing, invalid or revoked credentials.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Not permitted for this principal.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: >-
            The agent, or a resource under it, does not exist or is not visible
            to this key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limited. See Retry-After.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error. The message is generic; quote the request id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      x-codeSamples:
        - lang: bash
          label: curl
          source: >-
            curl -X POST
            "https://api.signalmd.dev/v1/agents/6f1d2c3b-4a5e-4f60-8b7a-9c0d1e2f3a4b/tests/validate"
            \
              -H "Authorization: Bearer $SIGNAL_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"spec":{"specVersion":1,"source":{"kind":"custom","basedOnTestId":null,"basedOnCallId":null},"caller":{"persona":"golden-cooperative","goal":"Ask what the cancellation policy is","lines":["What is your cancellation policy?"],"behaviours":[]},"fixtures":{"lookup_policy":[{"response":{"policy":"Free cancellation up to 24 hours before."}}]},"criteria":[{"text":"The agent states the cancellation window","decidedBy":"judge"}]}}'
components:
  schemas:
    ValidateTestRequest:
      type: object
      properties:
        spec:
          type: object
          additionalProperties: {}
          description: >-
            A TestSpec (see the TestSpec component and GET .../tests/schema).
            Checked as a whole: a refused spec names the first problem's path in
            `param`.
        testId:
          type: string
          format: uuid
          pattern: >-
            ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
          example: 3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f
          description: Check the spec as an edit of this test.
      required:
        - spec
      example:
        spec:
          specVersion: 1
          source:
            kind: custom
            basedOnTestId: null
            basedOnCallId: null
          caller:
            persona: golden-cooperative
            goal: Ask what the cancellation policy is
            lines:
              - What is your cancellation policy?
            behaviours: []
          fixtures:
            lookup_policy:
              - response:
                  policy: Free cancellation up to 24 hours before.
          criteria:
            - text: The agent states the cancellation window
              decidedBy: judge
    SpecValidation:
      type: object
      properties:
        object:
          type: string
          enum:
            - spec_validation
        ok:
          type: boolean
          description: Whether the spec would be stored.
        problems:
          type: array
          items:
            $ref: '#/components/schemas/SpecProblem'
        spec:
          allOf:
            - $ref: '#/components/schemas/TestSpec'
            - type:
                - object
                - 'null'
              description: >-
                The spec as it would be stored: ids filled in, personal data
                masked. Null when it is too broken to read.
      required:
        - object
        - ok
        - problems
        - spec
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              $ref: '#/components/schemas/ErrorType'
            code:
              type: string
              example: agent_not_found
              description: The specific reason; stable within v1.
            message:
              type: string
              example: Agent not found.
            param:
              type:
                - string
                - 'null'
              description: The request field at fault, for a validation error.
            requestId:
              type:
                - string
                - 'null'
              example: req_8c1f0e2b4a6d9e3f7a5c1b0d
            quota:
              type: object
              properties:
                metric:
                  type: string
                  example: credits
                  description: >-
                    credits when the workspace's monthly credits are used up, or
                    agents when the plan's agent limit is reached.
                activity:
                  type: string
                  enum:
                    - observation
                    - testing
                    - chat
                  example: testing
                  description: >-
                    With metric credits: what the request would have spent them
                    on. observation is analysing calls, testing is test runs,
                    chat is the copilot.
                requested:
                  type: integer
                  example: 18
                  description: >-
                    With metric credits: the credits the request needed to
                    start.
                limit:
                  type: integer
                  description: 'The plan''s limit: the month''s credits, or its agents.'
                used:
                  type: integer
                  description: How much of the limit is used this month.
                plan:
                  type: string
                  example: free_org
                  description: The workspace's plan slug.
                upgradePath:
                  type: string
                  example: /billing
                  description: Where in the web app the plan is changed.
              required:
                - metric
                - limit
                - used
                - plan
                - upgradePath
              description: >-
                Present when code is quota_exceeded: the plan limit the request
                would pass.
            proposalId:
              type: string
              format: uuid
              description: >-
                Present when code is criteria_locked: the pending criteria
                proposal the change was filed as. A person approves or rejects
                it.
          required:
            - type
            - code
            - message
            - param
            - requestId
      required:
        - error
      example:
        error:
          type: not_found_error
          code: agent_not_found
          message: Agent not found.
          param: null
          requestId: req_8c1f0e2b4a6d9e3f7a5c1b0d
    SpecProblem:
      type: object
      properties:
        path:
          type: string
          description: >-
            Where in the spec, as a JSON path: criteria[2].ref,
            fixtures.lookup[0].args.
        code:
          type: string
          description: >-
            The problem's kind, such as unknown_brief_ref, unknown_tool,
            personal_data.
        message:
          type: string
        severity:
          type: string
          enum:
            - error
            - warning
          description: An error stops the spec being stored; a warning does not.
      required:
        - path
        - code
        - message
        - severity
    TestSpec:
      type: object
      properties:
        specVersion:
          type: number
          enum:
            - 1
        testId:
          type: string
          format: uuid
          pattern: >-
            ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
          example: 3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f
          description: Output only.
        revision:
          type: integer
          description: Output only.
        source:
          type: object
          properties:
            kind:
              type: string
              enum:
                - production
                - custom
                - probe
              description: >-
                production: a stored call replayed. custom: written as a spec.
                probe: written for a brief line no call exercises; never gates.
            basedOnTestId:
              type:
                - string
                - 'null'
              format: uuid
              pattern: >-
                ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
              example: 3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f
              description: >-
                The test whose start, masking map and issue criterion this one
                borrows.
            basedOnCallId:
              type:
                - string
                - 'null'
              format: uuid
              pattern: >-
                ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
              example: 3f1c2d4e-5a6b-4c7d-8e9f-0a1b2c3d4e5f
              description: The stored call it is based on.
            briefLine:
              type:
                - object
                - 'null'
              properties:
                section:
                  type: string
                  enum:
                    - out_of_scope
                    - guardrails
                    - intent
                key:
                  type: string
                text:
                  type: string
              required:
                - section
                - key
                - text
              description: A probe's brief line.
            generated:
              type:
                - object
                - 'null'
              properties:
                generationId:
                  type: string
                kind:
                  type: string
                  enum:
                    - from_call
                    - written
                cell:
                  type: string
              required:
                - generationId
                - kind
                - cell
              description: Set when a test generation made it. Never read from input.
          required:
            - kind
            - basedOnTestId
            - basedOnCallId
        intentSlug:
          type:
            - string
            - 'null'
        lane:
          type:
            - string
            - 'null'
          enum:
            - hearing
            - understanding
            - flow
            - speaking
            - integrations
            - null
          description: >-
            The lane a defect lives in: hearing, understanding, flow, speaking
            or integrations.
        tier:
          type: string
          enum:
            - text
            - phone
        start:
          type: object
          properties:
            direction:
              type: string
              enum:
                - inbound
                - outbound
            agentSpeaksFirst:
              type:
                - boolean
                - 'null'
            variables:
              type: object
              additionalProperties:
                type: string
              description: Dynamic variables the call starts with, personal values masked.
            metadata:
              type: object
              additionalProperties: {}
          required:
            - direction
            - agentSpeaksFirst
            - variables
            - metadata
        caller:
          type: object
          properties:
            persona:
              type: string
              description: >-
                A persona slug from GET .../personas, or @source for the source
                call's own caller.
            goal:
              type: string
            lines:
              type:
                - array
                - 'null'
              items:
                type: string
              description: >-
                What the caller says. Null: the source call's own lines, read at
                run time.
            behaviours:
              type:
                - array
                - 'null'
              items:
                type: object
                properties:
                  kind:
                    type: string
                    enum:
                      - refuses
                      - asks_for_person
                      - off_topic
                      - repeats
                      - short_answers
                      - silent_after_question
                      - profile
                  atLine:
                    type:
                      - integer
                      - 'null'
                    description: 1-based caller line; null for the whole call.
                  detail:
                    type: string
                required:
                  - kind
                  - atLine
                  - detail
              description: 'Scripted caller behaviour. Null: the source call''s own.'
          required:
            - persona
            - goal
            - lines
            - behaviours
        fixtures:
          type: object
          additionalProperties:
            type: array
            items:
              $ref: '#/components/schemas/TestSpecFixture'
          description: Tool name to its mocked answers.
        criteria:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                description: Stable across revisions.
              ref:
                type: string
                description: A brief reference, goal or issue. Exactly one of ref and text.
              text:
                type: string
              polarity:
                type: string
                enum:
                  - must
                  - must_not
              decidedBy:
                type: string
                enum:
                  - detector
                  - judge
                  - unmeasured
                description: >-
                  What decides the criterion: a check on the transcript and tool
                  calls, a reading of the conversation, or nothing a text run
                  can measure.
            required:
              - id
              - decidedBy
        expect:
          type: string
          enum:
            - pass
            - fail
        guard:
          type: boolean
        sets:
          type: array
          items:
            type: string
          description: Names of test sets it belongs to.
        tags:
          type: array
          items:
            type: string
        title:
          type:
            - string
            - 'null'
      required:
        - specVersion
        - source
        - intentSlug
        - lane
        - tier
        - start
        - caller
        - fixtures
        - criteria
        - expect
        - guard
        - sets
        - tags
      description: >-
        A test as a JSON document: who calls, what each tool answers, and what
        must hold. GET .../tests/schema has its JSON Schema; POST
        .../tests/validate checks one.
    ErrorType:
      type: string
      enum:
        - invalid_request_error
        - authentication_error
        - budget_error
        - permission_error
        - not_found_error
        - conflict_error
        - rate_limit_error
        - api_error
    TestSpecFixture:
      type: object
      properties:
        args:
          description: >-
            The arguments this answer is for. Absent or null: the answer for any
            arguments no other entry matches.
        response:
          description: What the tool returns.
        success:
          type: boolean
          description: Whether the tool call succeeds. Default true.
        provenance:
          type: object
          properties:
            from:
              type: string
              enum:
                - source_call
                - other_call
                - owner
            callId:
              type: string
          required:
            - from
          description: 'Read only: where the answer came from. Ignored on input.'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An API key (`sig_...`), or a session token from the web app.

````

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