openapi: 3.0.3
info:
  title: SOAT Activity API
  version: 1.0.0
  description: >-
    API for the activity feed — "what did agents do today," one entry per
    autonomously executed action. Distinct from the audit log: the audit log is
    principal-centric (who did what to the platform); this feed is
    agent/run-centric (what an agent did during a run). There is no public
    create endpoint — entries are platform-written by producers (approval
    resolution, exception filing, schedule firing, tool execution). Cursor
    (keyset) paginated, not offset, because the feed is append-only and
    high-volume.
  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: Activity
    description: Read the autonomous-execution activity feed
security:
  - bearerAuth: []
paths:
  /api/v1/activity:
    get:
      tags:
        - Activity
      summary: List activity feed entries
      description: >-
        Returns activity entries for a project, newest first, filterable by
        kind, severity, agent, generation and orchestration run — every filter
        composable with the rest. Paginated with an opaque cursor rather than
        offset/limit — pass the previous page's `next_cursor` to fetch the
        next one; a `null` `next_cursor` means there is no more data.
      operationId: listActivity
      parameters:
        - name: project_id
          in: query
          description: Project ID (required if not using project key auth)
          schema:
            type: string
            example: proj_V1StGXR8Z5jdHi6B
        - name: kind
          in: query
          description: Filter by activity kind
          schema:
            type: string
            enum:
              [
                action_executed,
                approval_created,
                approval_resolved,
                exception_created,
                schedule_fired,
                share_cap_exceeded,
                share_resumed,
                share_revoked,
                share_suspended,
                tool_resolution_failed,
                usage_quantity_invalid,
              ]
        - name: severity
          in: query
          description: Filter by severity
          schema:
            type: string
            enum: [info, warning, critical]
        - name: agent_id
          in: query
          description: >-
            Filter to entries produced by one agent. Composable with every
            other filter — entries carry one agent, one generation and one run,
            so naming two narrows to the rows where both hold.
          schema:
            type: string
            example: agent_V1StGXR8Z5jdHi6B
        - name: generation_id
          in: query
          description: >-
            Filter to entries produced during one agent generation. This is
            what turns `tool_resolution_failed` from alertable into usable: the
            warning for a suspect turn is one query rather than a scan of the
            project's feed.
          schema:
            type: string
            example: gen_V1StGXR8Z5jdHi6B
        - name: orchestration_run_id
          in: query
          description: Filter to entries produced during one orchestration run.
          schema:
            type: string
            example: orch_run_V1StGXR8Z5jdHi
        - name: cursor
          in: query
          description: Opaque cursor from a previous page's `next_cursor`
          schema:
            type: string
        - $ref: './pagination.yaml#/components/parameters/Limit'
      responses:
        '200':
          description: Page of activity entries
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - next_cursor
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActivityEntry'
                  next_cursor:
                    type: string
                    nullable: true
                    description: Pass as `cursor` to fetch the next page; `null` when this is the last page
        '400':
          description: Malformed cursor
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '500':
          description: Internal server error
  /api/v1/activity/export:
    get:
      tags:
        - Activity
      summary: Export the activity feed as NDJSON
      description: >-
        Streams a project's activity entries as newline-delimited JSON — one
        entry object per line, **oldest first**, where the feed itself reads
        newest first: a feed answers what just happened, and a file is read
        start to end. `project_id` is required: the export is per-project by
        design. Filters behave exactly as they do on the list endpoint.
      operationId: exportActivity
      # Not a tool: the response is a stream with no JSON projection, and an
      # export is deliberately unbounded, so the callable form of "read the
      # activity feed" is `listActivity`, which is paged.
      x-soat-mcp-exclude: true
      parameters:
        - name: project_id
          in: query
          required: true
          description: Project whose activity is exported
          schema:
            type: string
            example: proj_V1StGXR8Z5jdHi6B
        - name: kind
          in: query
          description: Only entries of this kind
          schema:
            type: string
        - name: severity
          in: query
          description: Only entries of this severity
          schema:
            type: string
        - name: agent_id
          in: query
          description: Only entries an agent produced
          schema:
            type: string
            example: agent_V1StGXR8Z5jdHi6B
        - name: generation_id
          in: query
          description: Only entries a generation produced
          schema:
            type: string
            example: gen_V1StGXR8Z5jdHi6B
        - name: orchestration_run_id
          in: query
          description: Only entries an orchestration run produced
          schema:
            type: string
            example: orch_run_V1StGXR8Z5jdHi6B
      responses:
        '200':
          description: >-
            A newline-delimited stream of activity entries. Each line is a JSON
            object with the same fields as `ActivityEntry`.
          content:
            application/x-ndjson:
              schema:
                type: string
        '400':
          description: '`project_id` is required'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT token or sk_ api key
  schemas:
    ActivityEntry:
      type: object
      properties:
        id:
          type: string
          example: acte_V1StGXR8Z5jdHi6B
        project_id:
          x-soat-ref: projects
          type: string
        kind:
          type: string
          enum:
            [
              action_executed,
              approval_created,
              approval_resolved,
              exception_created,
              schedule_fired,
              share_cap_exceeded,
              share_resumed,
              share_revoked,
              share_suspended,
              tool_resolution_failed,
              usage_quantity_invalid,
            ]
          description: >-
            How the entry was produced. `tool_resolution_failed` means a tool
            binding contributed no tool to the turn — its source could not be
            reached or refused the listing, or the listing was read and left
            nothing to attach — so the turn ran without it. The generation
            itself completes, carrying no error, so this is the only signal
            that it answered with fewer tools than it was configured to have.
            `share_suspended`, `share_resumed` and `share_revoked` land in a
            consumer project when the publisher of a share it accepted
            suspends, resumes or revokes it; `ref_id` is the share and `detail`
            names the resource and the publisher project.
            `share_cap_exceeded` lands in the consumer project when a call
            through a share it accepted is refused by the share's `cap`.
            `usage_quantity_invalid` lands in the project a tool call is
            metered in when a resource price row's `quantity` reads no finite
            number >= 0; `ref_id` is the tool.
        severity:
          type: string
          enum: [info, warning, critical]
        summary:
          type: string
          description: One-line, human-readable description
        detail:
          type: object
          nullable: true
          description: >-
            Kind-specific structured context (tool, args digest, node id,
            guardrail policy version)
        orchestration_run_id:
          type: string
          nullable: true
          description: Originating orchestration run, if any
        agent_id:
          type: string
          nullable: true
          description: Associated agent, if any
        generation_id:
          type: string
          nullable: true
          description: >-
            The agent generation the entry was produced during, if any. Filter
            on it with the `generation_id` query parameter to read everything
            one turn did.
        ref_id:
          type: string
          nullable: true
          description: >-
            Producer-specific reference (the approval, exception, or trigger
            firing id the entry came from, or the executed tool's id)
        created_at:
          type: string
          format: date-time
