openapi: 3.0.3
info:
  title: SOAT Chains API
  version: 1.0.0
  description: >-
    API for continuation chains — the population of generations that descend
    from one root because each declared the previous one as its
    `initiator_generation_id`. A chain is created by the platform the first time
    a generation continues another (an approved or expired tool call, a session
    resumption); a generation that never continues one is not a chain and gets
    no record. Read-only: there is nothing for a caller to create, and the size
    a chain may reach is set on the agent (`stop_conditions`), not here.

    `status` is observability. Enforcement counts the chain's member generations
    directly, so a chain record can never let a runaway through — see the
    Chains module documentation.
  contact:
    name: SOAT Team
    url: https://github.com/ttoss/soat
servers:
  - url: '{baseUrl}'
    description: Base URL of your SOAT deployment (e.g. https://your-soat.com or http://localhost:5047)
    variables:
      baseUrl:
        description: The base URL of your SOAT deployment
        default: http://localhost:5047
tags:
  - name: Chains
    description: Inspect continuation chains and how large they have grown
security:
  - bearerAuth: []
paths:
  /api/v1/chains:
    get:
      tags:
        - Chains
      summary: List continuation chains
      description: >-
        Returns the continuation chains in a project, newest first. Filter by
        `status` to find the chains that may still be spending (`active`) or the
        ones a budget stopped (`budget_exhausted`).
      operationId: listChains
      parameters:
        - name: project_id
          in: query
          description: Project ID (required if not using project key auth)
          schema:
            type: string
            example: proj_V1StGXR8Z5jdHi6B
        - name: status
          in: query
          description: Filter by chain status
          schema:
            type: string
            enum: [active, concluded, expired, budget_exhausted]
        - name: agent_id
          in: query
          description: Filter by the agent whose continuation opened the chain
          schema:
            type: string
            example: agent_V1StGXR8Z5jdHi6B
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of results to skip
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: List of continuation chains
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Chain'
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '500':
          description: Internal server error
  /api/v1/chains/{chain_id}:
    get:
      tags:
        - Chains
      summary: Get a continuation chain
      description: >-
        Returns a single continuation chain. To read the generations in it, list
        generations filtered by `chain_id`.
      operationId: getChain
      parameters:
        - $ref: '#/components/parameters/chain_id'
      responses:
        '200':
          description: Continuation chain
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Chain'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Chain not found
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT token or sk_ api key
  parameters:
    chain_id:
      name: chain_id
      in: path
      required: true
      description: Continuation chain ID
      schema:
        type: string
        example: chain_V1StGXR8Z5jdHi6B
  schemas:
    Chain:
      type: object
      properties:
        id:
          type: string
          example: chain_V1StGXR8Z5jdHi6B
        project_id:
          x-soat-ref: projects
          type: string
        agent_id:
          x-soat-ref: agents
          type: string
          nullable: true
          description: >-
            The agent whose continuation opened the chain. A chain can span
            agents, so this names its origin rather than an owner. Held as a
            plain id, not a reference the platform maintains — deleting the
            agent leaves the chain record intact.
        status:
          type: string
          enum: [active, concluded, expired, budget_exhausted]
          description: >-
            `active` — hops are still being spawned.
            `concluded` — a member finished with nothing left pending; not
            terminal, since a decision months later can spawn another hop and
            put the chain back to `active`.
            `expired` — a held approval lapsed and the agent does not react to
            expiry, so nothing resumed it.
            `budget_exhausted` — a hop was refused by the chain budget.
        generation_count:
          type: integer
          description: >-
            Generations in the chain, the root included — the same population
            `GET /api/v1/generations?chain_id=<id>` returns. Re-derived on every
            hop, so it is a description of the chain, never the thing the budget
            is enforced against.
        last_generation_at:
          type: string
          format: date-time
          nullable: true
          description: When the chain last gained a generation
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
