---
openapi: 3.0.3
info:
  title: Pipelogiq External API
  version: 0.5.0
  description: |
    External API used by SDK clients and workers.

    Pipeline creation through `/pipelines/idempotent` is the opt-in reliable
    creation contract. Its idempotency key is unique within an application and
    is retained for the lifetime of the pipeline. Reusing a key with a different
    creation request returns `409`. The legacy `/pipelines` route is preserved
    and is not idempotent.

    This reference describes the current 0.5.0 source implementation. Individual
    operations declare their actual credential requirements. Compatibility fields
    that are accepted but not enforced are identified in their descriptions.
servers:
- url: http://localhost:8081
security:
- ApiKeyAuth: []
paths:
  "/pipelines":
    post:
      summary: Create a pipeline using the legacy non-idempotent contract
      description: |
        Preserved for existing SDK clients. Each successful request creates a
        new pipeline, even when the payload is identical. New integrations that
        must safely retry an unknown HTTP outcome should use
        `/pipelines/idempotent`.
      operationId: createPipelineLegacy
      tags:
      - Pipelines
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/LegacyPipelineCreateRequest"
      responses:
        '200':
          description: Pipeline created
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PipelineResponse"
        '400':
          description: Invalid request
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
            text/plain:
              schema:
                type: string
        '401':
          description: Invalid API key in the request body
        '500':
          description: Pipeline creation failed
  "/pipelines/idempotent":
    post:
      summary: Atomically create or resolve a pipeline by idempotency key
      description: |
        The key is scoped to the application authenticated by `X-API-Key` and
        is retained for the lifetime of the pipeline. Sequential and concurrent
        requests with the same key and the same creation intent return the same
        pipeline ID. Tracing metadata may change between retries. Reusing the
        key for a different creation intent returns `409`.
      operationId: createPipelineIdempotent
      tags:
      - Pipelines
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/IdempotentPipelineCreateRequest"
      responses:
        '201':
          description: A new pipeline was created
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/IdempotentPipelineCreateResponse"
        '200':
          description: The existing pipeline for this application and key was returned
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/IdempotentPipelineCreateResponse"
        '400':
          description: Validation error
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid X-API-Key header
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '409':
          description: The key was already used for a different creation intent
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '500':
          description: Pipeline creation failed
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/pipelines/by-idempotency-key":
    post:
      summary: Find a pipeline by its application-scoped idempotency key
      description: |
        Uses a request body so the idempotency key is not placed in the URL or
        routine access logs.
      operationId: getPipelineByIdempotencyKey
      tags:
      - Pipelines
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/PipelineIdempotencyLookupRequest"
      responses:
        '200':
          description: Pipeline status and stage details
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PipelineResponse"
        '400':
          description: Validation error
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid X-API-Key header
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: No pipeline exists for this application and key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/pipelines/{pipelineId}":
    get:
      summary: Get pipeline status and stage execution details
      operationId: getPipeline
      tags:
      - Pipelines
      parameters:
      - "$ref": "#/components/parameters/PipelineId"
      responses:
        '200':
          description: Pipeline status and stage details
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PipelineResponse"
        '400':
          description: Invalid pipeline ID
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Invalid API key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '403':
          description: Pipeline belongs to another application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: Pipeline not found
  "/pipelines/{pipelineId}/cancel":
    post:
      summary: Cancel a non-terminal pipeline
      description: |
        Atomically marks the authenticated application's pipeline and its
        unfinished stages as cancelled. Cancellation of an already-running
        handler is cooperative; stale results are fenced by execution metadata.
      operationId: cancelPipeline
      tags:
      - Pipelines
      parameters:
      - "$ref": "#/components/parameters/PipelineId"
      responses:
        '200':
          description: Pipeline cancelled
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PipelineResponse"
        '400':
          description: Invalid pipeline ID
        '401':
          description: Invalid API key
        '404':
          description: Pipeline not found for this application
        '409':
          description: Pipeline is already terminal and cannot be cancelled
        '504':
          description: Cancellation timed out
  "/pipelines/{pipelineId}/stages":
    post:
      summary: Append stages to an existing pipeline
      operationId: appendPipelineStages
      tags:
      - Pipelines
      parameters:
      - "$ref": "#/components/parameters/PipelineId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/AppendStagesRequest"
            examples:
              appendStages:
                value:
                  stages:
                  - stageName: agent.tool
                    stageHandlerName: AgentToolHandler
                    input: '{"toolName":"getOrder","args":{"id":"42"}}'
                    options:
                      runNextIfFailed: false
                      maxRetries: 3
                      retryInterval: 5
                      retryOnErrorCodes:
                      - TIMEOUT
                      - UPSTREAM_ERROR
                      - RATE_LIMIT_EXCEEDED
                      backoff: exponential
                      maxRetryInterval: 60
                      jitter: true
                    isEvent: false
      responses:
        '200':
          description: Stages appended
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/AppendStagesResponse"
              examples:
                appended:
                  value:
                    stages:
                    - id: 9021
                      pipelineId: 1307
                      name: agent.tool
                      stageHandlerName: AgentToolHandler
                      status: NotStarted
                      createdAt: '2026-03-10T10:14:05Z'
                      input: '{"toolName":"getOrder","args":{"id":"42"}}'
                      nextStageId:
                      isSkipped: false
                      isEvent: false
                      runNextIfCurrentFailed: false
        '400':
          description: Validation error
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: Pipeline not found
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '409':
          description: Pipeline is terminal, append is not allowed
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/stages/{stageId}/resume":
    post:
      summary: Resume a stage waiting for external approval
      operationId: resumeStageApproval
      tags:
      - Stages
      parameters:
      - "$ref": "#/components/parameters/StageId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ResumeStageRequest"
            examples:
              approved:
                value:
                  approved: true
              rejected:
                value:
                  approved: false
                  rejectionReason: User rejected payment mutation
      responses:
        '204':
          description: Stage resumed
        '400':
          description: Validation error
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: Stage not found
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '409':
          description: Stage not waiting for approval or conflicting repeated decision
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/stages/{stageId}/lease/acquire":
    post:
      summary: Acquire the lease for a dispatched stage execution
      description: |
        Worker protocol endpoint. The worker session token binds the lease to
        the authenticated worker session. `acquired=false` is a successful
        response indicating that the delivery must not execute the handler.

        The current lease duration is 60 seconds. A repeated acquisition is not
        reentrant: an active Running execution returns lease_held, including when
        the caller previously acquired it. The application comes from the session.
      operationId: acquireStageLease
      tags:
      - Worker protocol
      security:
      - WorkerSessionAuth: []
      parameters:
      - "$ref": "#/components/parameters/StageId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/StageLeaseRequest"
      responses:
        '200':
          description: Lease decision
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/StageLeaseResponse"
        '400':
          description: Invalid stage ID or request body
        '401':
          description: Missing or invalid worker session token
        '500':
          description: Lease operation failed
  "/stages/{stageId}/lease/renew":
    post:
      summary: Renew the lease for a running stage execution
      description: |
        Worker-session endpoint. Renewal succeeds only for the current Running
        execution and lease owner while its lease remains unexpired. Success extends
        the execution lease by 60 seconds. It does not extend the HTTP delivery token's
        visibility timeout. On a definitive refusal, stop further handler side effects
        cooperatively. Server-side fencing and recovery determine which result applies.
      operationId: renewStageLease
      tags:
      - Worker protocol
      security:
      - WorkerSessionAuth: []
      parameters:
      - "$ref": "#/components/parameters/StageId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/StageLeaseRequest"
      responses:
        '200':
          description: Lease renewal decision
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/StageLeaseResponse"
        '400':
          description: Invalid stage ID or request body
        '401':
          description: Missing or invalid worker session token
        '500':
          description: Lease operation failed
  "/jobs/pull":
    post:
      summary: Pull the next stage job for a handler queue
      description: |
        HTTP gateway over the authenticated application's StageNext queues. Only the
        application API key is checked; worker-session validation occurs on lease and
        result operations. A queue outside this application's handler pattern is 403.

        waitSeconds defaults to zero and accepts 0..20. A positive value polls roughly
        every 250 ms until a message arrives or the deadline produces 204.

        A 200 response includes a process-local acknowledgement token. The delivery
        remains unacknowledged at the broker until acknowledged or requeued. Expiry
        sweeps attempt requeue after GATEWAY_VISIBILITY_TIMEOUT (default 60 seconds).
        Lease renewal does not extend that delivery timeout. GATEWAY_MAX_INFLIGHT
        defaults to 128 pending deliveries per API process; capacity exhaustion is 429.
      operationId: pullJob
      tags:
      - Worker protocol
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/PullJobRequest"
      responses:
        '200':
          description: A stage job was dequeued
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/PullJobResponse"
        '204':
          description: No message available before the deadline
        '400':
          description: Missing queue, or waitSeconds outside 0..20
        '401':
          description: Missing or invalid API key
        '403':
          description: Queue does not belong to this application
        '429':
          description: Too many in-flight messages; back off and retry
        '500':
          description: Pull failed
  "/jobs/ack":
    post:
      summary: Acknowledge or requeue a pulled stage job
      description: |
        The opaque body token authorizes acknowledgement; this handler does not check
        an API key or worker session. Protect the token as a credential.

        For executed work, send requeue:false only after the result endpoint returned
        202. Stale or duplicate deliveries rejected by lease acquisition may be
        acknowledged without executing. requeue:true returns a delivery to the broker;
        it does not reset an execution lease or itself create a new execution attempt.

        Tokens are held by the API process that performed the pull. Route pull and ack
        to the same instance. A 404 means that process does not hold the token: it may
        have expired, been acknowledged, or belong to another replica. A 404 does not
        prove that requeue succeeded. Repeated acknowledgement is not idempotent.
      operationId: ackJob
      tags:
      - Worker protocol
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/AckJobRequest"
      responses:
        '200':
          description: Acknowledgement applied
        '400':
          description: Missing token
        '404':
          description: Token not held by this API process (including expired or previously
            acknowledged tokens)
        '500':
          description: Acknowledgement failed
      security: []
  "/stages/{stageId}/result":
    post:
      summary: Report a stage result over HTTP
      description: |
        Requires an application API key and a valid worker session for that application.
        Validates the stage's application ownership and message shape, then publishes
        persistently with broker confirms. A 202 means broker acceptance, not an applied
        database update. Stale or duplicate results may be accepted and later discarded
        by the asynchronous result consumer's execution-ID/attempt fencing.

        The result string is limited to 262144 bytes; the complete JSON request body is
        limited to 327680 bytes. Unknown fields are accepted for SDK compatibility and
        ignored if the server message type does not recognize them. Acknowledge the
        original pulled delivery after 202. On an unknown result-posting outcome, retry
        the same computed result and execution identity rather than rerunning effects.
      operationId: postStageResult
      tags:
      - Worker protocol
      security:
      - ApiKeyAuth: []
        WorkerSessionAuth: []
      parameters:
      - "$ref": "#/components/parameters/StageId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/StageResultSubmit"
      responses:
        '202':
          description: Result queued for the stage result consumer
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/StageResultAccepted"
        '400':
          description: Validation failed
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing, invalid, expired, or application-mismatched worker
            session, or missing/invalid API key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '403':
          description: Stage belongs to another application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: Stage not found
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '503':
          description: Message broker unavailable; retry the request
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '500':
          description: Session, stage ownership, or result encoding operation failed
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules":
    get:
      summary: List the application's schedules
      operationId: listSchedules
      tags:
      - Schedules
      parameters:
      - name: status
        in: query
        schema:
          type: string
          enum:
          - Active
          - Paused
          - Archived
      - name: cursor
        in: query
        schema:
          type: string
      - name: limit
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
      responses:
        '200':
          description: A page of schedules, each with a recent-run health summary
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ScheduleListResponse"
        '400':
          description: Invalid status filter or limit
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}":
    put:
      summary: Create or update a schedule
      description: |
        Idempotent upsert keyed on the application-scoped, case-insensitive name.

        An unchanged body returns `200` without bumping `definitionVersion` or
        moving `nextRunAt`, so re-applying the same schedule on every deploy is a
        no-op. A changed body returns `200` with a new version and a re-planned
        next run. A new name returns `201`. Re-applying an archived schedule
        brings it back Active.

        `definition` is validated by the same rules as `POST /pipelines`.
      operationId: upsertSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ScheduleUpsertRequest"
      responses:
        '201':
          description: A new schedule was created
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '200':
          description: The existing schedule was updated or left unchanged
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '400':
          description: Validation failed, with per-field messages
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '500':
          description: The schedule could not be stored
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
    get:
      summary: Get one schedule
      operationId: getSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      responses:
        '200':
          description: Definition, policies, next and last run, health summary
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '400':
          description: Invalid schedule name
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}/runs":
    get:
      summary: List a schedule's run history
      operationId: listScheduleRuns
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      - name: cursor
        in: query
        schema:
          type: string
      - name: limit
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 50
      responses:
        '200':
          description: A page of runs, newest first
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ScheduleRunListResponse"
        '400':
          description: Invalid schedule name or limit
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}/pause":
    post:
      summary: Pause a schedule
      description: Stops creating pipelines. The definition and history are kept.
      operationId: pauseSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      responses:
        '200':
          description: The paused schedule
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '401':
          description: Missing or invalid API key
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}/resume":
    post:
      summary: Resume a schedule
      description: |
        Recomputes `nextRunAt` from now, so a schedule paused for a week does not
        wake up owing a week of ticks whatever its catch-up policy says.
      operationId: resumeSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      responses:
        '200':
          description: The resumed schedule
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '400':
          description: The stored schedule can no longer be planned
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '409':
          description: The schedule has no future run (a Once schedule already past)
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}/archive":
    post:
      summary: Archive a schedule
      description: Terminal. Re-applying the definition with PUT brings it back Active.
      operationId: archiveSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      responses:
        '200':
          description: The archived schedule
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Schedule"
        '401':
          description: Missing or invalid API key
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/schedules/{name}/trigger":
    post:
      summary: Run a schedule immediately
      description: |
        Creates a run with `trigger: Manual` right away. It does not move the
        schedule's cursor, and overlap and catch-up policies do not apply — a
        manual run was explicitly asked for. The optional `input` replaces the
        first stage's input.
      operationId: triggerSchedule
      tags:
      - Schedules
      parameters:
      - "$ref": "#/components/parameters/ScheduleName"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/ScheduleTriggerRequest"
      responses:
        '201':
          description: The manual run and its pipeline
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/ScheduleTriggerResponse"
        '400':
          description: Invalid payload
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '401':
          description: Missing or invalid API key
        '404':
          description: No such schedule in this application
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
        '409':
          description: The schedule is archived
          content:
            application/problem+json:
              schema:
                "$ref": "#/components/schemas/ProblemDetails"
  "/version":
    get:
      summary: Server version and licence tier
      operationId: getVersion
      tags:
      - System
      security: []
      responses:
        '200':
          description: Build metadata
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/VersionInfo"
  "/logs":
    post:
      summary: Record a legacy free-form log line
      description: |
        Legacy log ingestion. This handler does not authenticate request headers. An
        optional body apiKey associates the log with an application when its hash
        matches a non-disabled key. Missing or unmatched keys still permit an unscoped
        log; this lookup does not check key expiry. It does not return 401 for key
        validation. Prefer stage-result logs or worker events for worker integrations.
      operationId: saveLog
      tags:
      - Application
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/LogRequest"
      responses:
        '200':
          description: Log line stored
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/LogResponse"
        '400':
          description: Malformed body
        '500':
          description: Log or keywords could not be stored
      security: []
  "/workers/bootstrap":
    post:
      summary: Register a worker and receive its session
      description: |
        Register a worker using an application API key and receive its workerId and
        session token. Send X-Worker-Session to lease, result, heartbeat, events, and
        shutdown operations; result submission also requires X-API-Key. HTTP workers
        use jobs/pull and ignore messageBroker.connectionString.

        WORKER_SESSION_TTL defaults to 24 hours. Heartbeats do not extend expiry.
        Rebootstrap of an existing application/instanceId reuses the worker record and
        replaces its token. Concurrent processes must use different instance IDs.
      operationId: bootstrapWorker
      tags:
      - Worker protocol
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WorkerBootstrapRequest"
      responses:
        '200':
          description: Worker registered
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/WorkerBootstrapResponse"
        '400':
          description: Malformed body
        '401':
          description: Missing or invalid API key
        '503':
          description: Broker hand-out is enabled but no broker address is configured
        '500':
          description: Application resolution or worker registration failed
  "/workers/heartbeat":
    post:
      summary: Report worker liveness and counters
      operationId: workerHeartbeat
      tags:
      - Worker protocol
      security:
      - WorkerSessionAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WorkerHeartbeatRequest"
      responses:
        '200':
          description: Heartbeat recorded
        '400':
          description: Malformed body
        '401':
          description: Missing worker session token or token does not match workerId;
            heartbeat/events also reject expired sessions
        '500':
          description: Worker state or events could not be persisted
      description: Records liveness and optional counters. Requires a valid, unexpired
        worker session matching workerId. Does not extend the session expiry.
  "/workers/events":
    post:
      summary: Append worker lifecycle events
      description: |
        Batched, at most `WORKER_EVENTS_MAX_BATCH` events per call. Events feed
        the dashboard's worker activity feed and alerting.
      operationId: workerEvents
      tags:
      - Worker protocol
      security:
      - WorkerSessionAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WorkerEventsRequest"
      responses:
        '200':
          description: Events recorded
        '400':
          description: Malformed body or batch too large
        '401':
          description: Missing worker session token or token does not match workerId;
            heartbeat/events also reject expired sessions
        '500':
          description: Worker state or events could not be persisted
  "/workers/shutdown":
    post:
      summary: Announce a graceful shutdown
      operationId: workerShutdown
      tags:
      - Worker protocol
      security:
      - WorkerSessionAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/WorkerShutdownRequest"
      responses:
        '200':
          description: Worker marked stopped
        '400':
          description: Malformed body
        '401':
          description: Missing worker session token or token does not match workerId;
            heartbeat/events also reject expired sessions
        '500':
          description: Worker state or events could not be persisted
      description: Marks the matching worker record stopped and records a lifecycle
        event. This is not token revocation; the handler matches workerId and the
        stored token but does not check session expiry.
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Application API key in X-API-Key. Individual operations declare
        whether this credential is checked; legacy pipeline creation instead reads
        body apiKey.
    WorkerSessionAuth:
      type: apiKey
      in: header
      name: X-Worker-Session
      description: Worker session token returned by bootstrap. Use X-Worker-Session
        alongside X-API-Key where both are required. Do not put both identities in
        one bearer credential.
  parameters:
    PipelineId:
      name: pipelineId
      in: path
      required: true
      description: Pipeline ID (> 0)
      schema:
        type: integer
        minimum: 1
    ScheduleName:
      name: name
      in: path
      required: true
      description: Application-scoped schedule name, matched case-insensitively.
      schema:
        type: string
        minLength: 1
        maxLength: 200
    StageId:
      name: stageId
      in: path
      required: true
      description: Stage ID (> 0)
      schema:
        type: integer
        minimum: 1
  schemas:
    PipelineDefinition:
      type: object
      required:
      - name
      - stages
      properties:
        apiKey:
          type: string
          writeOnly: true
          deprecated: true
          description: Required only by the legacy `/pipelines` endpoint; ignored
            by the idempotent endpoint.
        name:
          type: string
          minLength: 1
          maxLength: 255
        traceId:
          type: string
          maxLength: 36
          description: Optional tracing identifier; not part of idempotency intent
            comparison.
        policies:
          type: array
          items:
            type: object
            additionalProperties: true
        stages:
          type: array
          minItems: 1
          maxItems: 100
          items:
            "$ref": "#/components/schemas/StageCreate"
        pipelineKeywords:
          type: array
          maxItems: 64
          items:
            "$ref": "#/components/schemas/PipelineKeyword"
        pipelineContextItems:
          type: array
          maxItems: 64
          description: Do not use pipeline context as the consumer's sole business
            system of record.
          items:
            "$ref": "#/components/schemas/ContextItem"
    LegacyPipelineCreateRequest:
      allOf:
      - "$ref": "#/components/schemas/PipelineDefinition"
      - type: object
        required:
        - apiKey
    IdempotentPipelineCreateRequest:
      allOf:
      - "$ref": "#/components/schemas/PipelineDefinition"
      - type: object
        required:
        - idempotencyKey
        properties:
          idempotencyKey:
            type: string
            minLength: 1
            maxLength: 200
            description: Application-scoped key retained for the lifetime of the pipeline.
    IdempotentPipelineCreateResponse:
      type: object
      required:
      - pipeline
      - created
      - wasExisting
      properties:
        pipeline:
          "$ref": "#/components/schemas/PipelineResponse"
        created:
          type: boolean
          description: True only when this request inserted the pipeline.
        wasExisting:
          type: boolean
          description: True when an existing pipeline for the key was returned.
    PipelineIdempotencyLookupRequest:
      type: object
      required:
      - idempotencyKey
      properties:
        idempotencyKey:
          type: string
          minLength: 1
          maxLength: 200
    PipelineResponse:
      type: object
      required:
      - id
      - name
      - status
      - createdAt
      - isTerminal
      properties:
        id:
          type: integer
        name:
          type: string
        traceId:
          type: string
        status:
          type: string
          enum:
          - NotStarted
          - Pending
          - Running
          - Paused
          - Completed
          - Failed
          - Cancelled
        createdAt:
          type: string
          format: date-time
        finishedAt:
          type: string
          format: date-time
          nullable: true
        applicationId:
          type: integer
        stageStatuses:
          type: array
          items:
            type: string
        stages:
          type: array
          items:
            "$ref": "#/components/schemas/StageResponse"
        pipelineContextItems:
          type: array
          description: Sensitive values are returned as `[REDACTED]` while preserving
            `isSensitive=true`.
          items:
            "$ref": "#/components/schemas/ContextItem"
        pipelineKeywords:
          type: array
          items:
            "$ref": "#/components/schemas/PipelineKeyword"
        isEvent:
          type: boolean
        idempotencyKey:
          type: string
          description: Present for pipelines created through the idempotent contract.
        isTerminal:
          type: boolean
          description: True for Completed, Failed, or Cancelled pipeline status.
        wasExisting:
          type: boolean
          description: Compatibility field; creation outcome is authoritative in the
            idempotent response wrapper.
    StageCreate:
      type: object
      required:
      - stageName
      - stageHandlerName
      properties:
        stageName:
          type: string
          minLength: 1
          maxLength: 255
        stageHandlerName:
          type: string
          minLength: 1
          maxLength: 300
        description:
          type: string
          maxLength: 255
        input:
          type: string
          description: JSON-serialized input payload, at most 262144 bytes.
        policies:
          type: array
          items:
            type: object
            additionalProperties: true
        options:
          "$ref": "#/components/schemas/StageOptions"
        isEvent:
          type: boolean
        runNextIfFailed:
          type: boolean
          description: Compatibility field. Standard pipeline creation uses options.runNextIfFailed;
            set the option to configure continuation after a failed dependency.
    StageInfo:
      type: object
      required:
      - stageName
      - stageHandlerName
      properties:
        stageName:
          type: string
          minLength: 1
          maxLength: 255
        stageHandlerName:
          type: string
          minLength: 1
          maxLength: 300
        description:
          type: string
          maxLength: 255
        input:
          description: Any JSON value is accepted. Strings are unwrapped; other non-null
            JSON values are serialized as the stage input string. Omitted or null
            input becomes empty.
        policies:
          type: array
          items:
            type: object
            additionalProperties: true
        options:
          "$ref": "#/components/schemas/StageOptions"
        isEvent:
          type: boolean
        runNextIfFailed:
          type: boolean
          description: Continuation setting for this appended stage; options.runNextIfFailed
            takes precedence.
        stageId:
          type: integer
          nullable: true
          description: Compatibility field; ignored.
        pipelineId:
          type: integer
          nullable: true
          description: Compatibility field; ignored.
        runNextIfCurrentFailed:
          type: boolean
          description: Compatibility alias; when present, overrides top-level runNextIfFailed.
            options.runNextIfFailed takes precedence over both aliases.
      description: Stage appended by the external append API. stageId and pipelineId
        are ignored; the URL chooses the pipeline.
    StageOptions:
      type: object
      properties:
        runNextIfFailed:
          type: boolean
          description: Allows this stage to proceed when a required earlier stage
            failed. Set this on the dependent stage.
        retryInterval:
          type: integer
          minimum: 0
          description: Base retry delay in seconds. StageOptions automatic retry requires
            both retryInterval > 0 and maxRetries > 0.
        maxRetries:
          type: integer
          minimum: 0
          description: Maximum number of automatic retries after the first execution.
        timeOut:
          type: integer
          minimum: 1
          description: Handler timeout in seconds.
        retryOnErrorCodes:
          type: array
          description: |
            When non-empty, StageOptions retries only matching error codes.
            Terminal codes such as BUSINESS_REJECTED, VALIDATION_ERROR,
            INVALID_STATE, and MISSING_REQUIRED_DATA are never retried
            automatically.
          items:
            type: string
            minLength: 1
        backoff:
          type: string
          enum:
          - fixed
          - linear
          - exponential
          default: fixed
        maxRetryInterval:
          type: integer
          minimum: 1
          description: Maximum retry delay in seconds.
        jitter:
          type: boolean
          default: false
        dependsOn:
          type: array
          items:
            type: string
          description: Names of stages in this pipeline. When omitted or empty, the
            dispatcher waits for all earlier stages. Use exact stage names, not stage
            IDs or cross-pipeline references.
        runInParallelWith:
          type: array
          items:
            type: string
          description: Stored compatibility metadata; the current server dispatcher
            does not use this field to enable parallel execution. Use supported dependency
            behavior.
        failIfOutputEmpty:
          type: boolean
          description: Stored compatibility metadata; the current server result consumer
            does not enforce empty-output failure.
        notifyOnFailure:
          type: boolean
          description: Stored compatibility metadata; this field does not enable the
            current server alerting configuration.
        runAsUser:
          type: string
          description: Stored compatibility metadata; the current server does not
            impersonate this user when executing a handler.
    StageResponse:
      type: object
      required:
      - id
      - pipelineId
      - name
      - createdAt
      - isTerminal
      properties:
        id:
          type: integer
        pipelineId:
          type: integer
        spanId:
          type: string
        name:
          type: string
        stageHandlerName:
          type: string
        description:
          type: string
        status:
          type: string
          enum:
          - NotStarted
          - Running
          - Pending
          - RetryScheduled
          - Throttled
          - WaitingForApproval
          - Completed
          - Failed
          - Skipped
          - Cancelled
        createdAt:
          type: string
          format: date-time
        finishedAt:
          type: string
          format: date-time
          nullable: true
        startedAt:
          type: string
          format: date-time
          nullable: true
        nextRetryAt:
          type: string
          format: date-time
          nullable: true
        output:
          type: string
          nullable: true
        input:
          type: string
          nullable: true
        isSkipped:
          type: boolean
        isEvent:
          type: boolean
        nextStageId:
          type: integer
          nullable: true
        logs:
          type: array
          items:
            "$ref": "#/components/schemas/StageLog"
        options:
          "$ref": "#/components/schemas/StageOptions"
        failureCount:
          type: integer
          minimum: 0
        lastFailedAt:
          type: string
          format: date-time
          nullable: true
        hasFailureHistory:
          type: boolean
        attempt:
          type: integer
          minimum: 0
          description: Stable 1-based execution attempt for the current dispatched
            execution; zero before first dispatch.
        retryAttempt:
          type: integer
          minimum: 0
          description: Number of retries scheduled so far.
        lastErrorCode:
          type: string
          description: Last handler or timeout error code.
        failureDisposition:
          type: string
          enum:
          - retryable
          - terminal
        isTerminal:
          type: boolean
          description: True for Completed, Failed, Skipped, or Cancelled stage status.
    ContextItem:
      type: object
      required:
      - key
      properties:
        key:
          type: string
          minLength: 1
          maxLength: 300
        value:
          type: string
          description: String value, defaulting to empty when omitted. Idempotent
            pipeline creation limits it to 65536 bytes. Status reads redact sensitive
            values. Ignored for a worker-result tombstone.
        valueType:
          type: string
        isSensitive:
          type: boolean
          default: false
          description: Marks the value for redaction from status responses and persisted
            logs.
        isDeleted:
          type: boolean
          default: false
          description: In worker-result context updates, removes this key; value is
            ignored. Intended for updates, not initial pipeline context.
    PipelineKeyword:
      type: object
      required:
      - key
      - value
      properties:
        key:
          type: string
          minLength: 1
          maxLength: 300
        value:
          type: string
          minLength: 1
          maxLength: 300
    StageLog:
      type: object
      required:
      - message
      - created
      properties:
        id:
          type: integer
        stageId:
          type: integer
        message:
          type: string
        logLevel:
          type: string
        created:
          type: string
          format: date-time
    AppendStagesRequest:
      type: object
      required:
      - stages
      properties:
        stages:
          type: array
          minItems: 1
          items:
            "$ref": "#/components/schemas/StageInfo"
    AppendStagesResponse:
      type: object
      required:
      - stages
      properties:
        stages:
          type: array
          items:
            "$ref": "#/components/schemas/StageDto"
    StageDto:
      type: object
      required:
      - id
      - pipelineId
      - name
      - stageHandlerName
      - status
      - createdAt
      - isSkipped
      - isEvent
      - runNextIfCurrentFailed
      properties:
        id:
          type: integer
        pipelineId:
          type: integer
        name:
          type: string
        stageHandlerName:
          type: string
        status:
          type: string
        createdAt:
          type: string
          format: date-time
        input:
          type: string
        nextStageId:
          type: integer
          nullable: true
        isSkipped:
          type: boolean
        isEvent:
          type: boolean
        runNextIfCurrentFailed:
          type: boolean
        finishedAt:
          type: string
          format: date-time
          nullable: true
        startedAt:
          type: string
          format: date-time
          nullable: true
    ResumeStageRequest:
      type: object
      required:
      - approved
      properties:
        approved:
          type: boolean
        rejectionReason:
          type: string
          nullable: true
    StageLeaseRequest:
      type: object
      required:
      - executionId
      - workerId
      properties:
        executionId:
          type: string
          minLength: 1
          description: Opaque execution token received in the stage delivery.
        workerId:
          type: string
          minLength: 1
          description: Worker ID associated with the authenticated worker session.
    StageLeaseResponse:
      type: object
      required:
      - acquired
      properties:
        acquired:
          type: boolean
        attempt:
          type: integer
          minimum: 1
          description: Execution attempt accepted by the server.
        leaseExpiresAt:
          type: string
          format: date-time
          nullable: true
        reason:
          type: string
          description: Machine-readable explanation when acquired is false.
    PullJobRequest:
      type: object
      required:
      - queue
      properties:
        queue:
          type: string
          description: 'StageNext queue of this application: app_{applicationId}_{handler}_StageNext.'
        waitSeconds:
          type: integer
          minimum: 0
          maximum: 20
          default: 0
          description: Seconds to wait for a message before answering 204.
    PullJobResponse:
      type: object
      required:
      - token
      - queue
      - payload
      properties:
        token:
          type: string
          description: Opaque credential for jobs/ack, held in the API process that
            performed this pull. Separate from the execution lease.
        queue:
          type: string
        messageId:
          type: string
        payload:
          "$ref": "#/components/schemas/StageNextMessage"
        headers:
          type: object
          additionalProperties: true
    AckJobRequest:
      type: object
      required:
      - token
      properties:
        token:
          type: string
          minLength: 1
        requeue:
          type: boolean
          default: false
          description: True returns the message to the queue instead of acknowledging
            it.
    StageResultSubmit:
      type: object
      required:
      - stageId
      - executionId
      - attempt
      properties:
        pipelineId:
          type: integer
          nullable: true
          description: Pipeline the stage belongs to, as delivered in the stage job.
        stageId:
          type: integer
          minimum: 1
          description: Must equal the stageId in the route.
        executionId:
          type: string
          minLength: 1
          description: Execution token from the stage delivery; the consumer fences
            on it.
        attempt:
          type: integer
          minimum: 1
          description: Execution attempt accepted by the lease.
        isSuccess:
          type: boolean
          default: false
          description: Always send explicitly. Omission decodes as false.
        result:
          type: string
          description: Handler output, at most 262144 bytes.
        isWaitingForApproval:
          type: boolean
          description: Parks the stage in WaitingForApproval instead of completing
            it.
        errorCode:
          type: string
          description: Failure classification; must not contain control characters.
        retryable:
          type: boolean
          nullable: true
          description: False disables automatic retries. True does not override terminal
            error codes or create retry configuration; an applicable policy or StageOptions
            retry configuration is still required.
        nextStageId:
          type: integer
          nullable: true
          description: Accepted compatibility field; the current result consumer does
            not use it to route execution.
        runNextIfCurrentFailed:
          type: boolean
          description: Accepted compatibility field; the current result consumer does
            not use it. Configure continuation on the dependent stage with options.runNextIfFailed.
        logs:
          type: array
          items:
            "$ref": "#/components/schemas/StageResultLog"
        contextItems:
          type: array
          items:
            "$ref": "#/components/schemas/ContextItem"
        appendedStages:
          type: array
          items:
            "$ref": "#/components/schemas/WorkerAppendedStage"
    StageResultLog:
      type: object
      required:
      - message
      properties:
        message:
          type: string
        logLevel:
          type: string
        created:
          type: string
          format: date-time
    StageResultAccepted:
      type: object
      required:
      - accepted
      - stageId
      properties:
        accepted:
          type: boolean
        stageId:
          type: integer
        executionId:
          type: string
    ScheduleUpsertRequest:
      type: object
      required:
      - kind
      - definition
      properties:
        kind:
          type: string
          enum:
          - Cron
          - Interval
          - Once
        cronExpression:
          type: string
          description: |
            Standard 5-field cron, or @every <duration>, @hourly, @daily,
            @midnight. Six-field (seconds) expressions are not accepted.
        timeZone:
          type: string
          default: UTC
          description: IANA zone. Ticks are computed here and stored in UTC.
        intervalSeconds:
          type: integer
          minimum: 10
          nullable: true
        runAt:
          type: string
          format: date-time
          nullable: true
          description: Required for Once, and must be in the future.
        overlapPolicy:
          type: string
          enum:
          - Skip
          - Queue
          - Replace
          - Allow
          description: New schedules default to Skip. On an existing schedule, omission
            preserves the stored policy. Allow permits concurrent runs. This reference
            does not promise strict cross-pipeline serialization for Queue.
        catchupPolicy:
          type: string
          enum:
          - None
          - One
          - All
          description: New schedules default to None. On an existing schedule, omission
            preserves the stored policy.
        catchupMax:
          type: integer
          minimum: 1
          maximum: 1000
          default: 10
        jitterSeconds:
          type: integer
          minimum: 0
          maximum: 3600
          default: 0
        definition:
          "$ref": "#/components/schemas/PipelineDefinition"
    Schedule:
      type: object
      required:
      - id
      - applicationId
      - name
      - status
      - kind
      - timeZone
      - definition
      - definitionVersion
      - overlapPolicy
      - catchupPolicy
      - catchupMax
      - jitterSeconds
      - createdAt
      - updatedAt
      properties:
        id:
          type: integer
          format: int64
        applicationId:
          type: integer
        name:
          type: string
        status:
          type: string
          enum:
          - Active
          - Paused
          - Archived
        kind:
          type: string
          enum:
          - Cron
          - Interval
          - Once
        cronExpression:
          type: string
        timeZone:
          type: string
        intervalSeconds:
          type: integer
          nullable: true
        runAt:
          type: string
          format: date-time
          nullable: true
        definition:
          "$ref": "#/components/schemas/PipelineDefinition"
        definitionVersion:
          type: integer
          description: Incremented only when something that changes behaviour changed.
        overlapPolicy:
          type: string
          enum:
          - Skip
          - Queue
          - Replace
          - Allow
        catchupPolicy:
          type: string
          enum:
          - None
          - One
          - All
        catchupMax:
          type: integer
        jitterSeconds:
          type: integer
        nextRunAt:
          type: string
          format: date-time
          nullable: true
        lastRunAt:
          type: string
          format: date-time
          nullable: true
        lastRunStatus:
          type: string
          enum:
          - Created
          - Skipped
          - Failed
        createdBy:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        health:
          "$ref": "#/components/schemas/ScheduleHealth"
    ScheduleHealth:
      type: object
      description: Summary of the last 20 runs, for the dashboard list.
      properties:
        recentRuns:
          type: integer
        recentFailed:
          type: integer
        recentSkipped:
          type: integer
        outcomes:
          type: array
          maxItems: 20
          description: Newest first.
          items:
            type: string
            enum:
            - Created
            - Skipped
            - Failed
        lagSeconds:
          type: number
          nullable: true
    ScheduleRun:
      type: object
      required:
      - id
      - scheduleId
      - scheduledFor
      - firedAt
      - trigger
      - outcome
      - definitionVersion
      - lagSeconds
      properties:
        id:
          type: integer
          format: int64
        scheduleId:
          type: integer
          format: int64
        scheduledFor:
          type: string
          format: date-time
          description: The planned tick.
        firedAt:
          type: string
          format: date-time
        trigger:
          type: string
          enum:
          - Cron
          - Interval
          - Once
          - Manual
          - Catchup
        outcome:
          type: string
          enum:
          - Created
          - Skipped
          - Failed
        skipReason:
          type: string
          enum:
          - Overlap
          - Paused
          - Catchup
          - NoWorker
          description: NoWorker means an automatic tick was skipped because the application
            had no live registered worker. Manual triggers bypass this automatic liveness
            gate.
        pipelineId:
          type: integer
          nullable: true
        definitionVersion:
          type: integer
        error:
          type: string
          description: Present when outcome is Failed. The schedule keeps ticking.
        lagSeconds:
          type: number
          description: firedAt minus scheduledFor.
        pipelineStatus:
          type: string
        pipelineFinishedAt:
          type: string
          format: date-time
          nullable: true
    ScheduleListResponse:
      type: object
      required:
      - schedules
      properties:
        schedules:
          type: array
          items:
            "$ref": "#/components/schemas/Schedule"
        nextCursor:
          type: string
    ScheduleRunListResponse:
      type: object
      required:
      - runs
      properties:
        runs:
          type: array
          items:
            "$ref": "#/components/schemas/ScheduleRun"
        nextCursor:
          type: string
    ScheduleTriggerRequest:
      type: object
      properties:
        input:
          description: Optional non-null JSON value replacing the first stage input.
            The raw JSON representation is stored, including JSON string quotation
            marks. Omitted or null input leaves the definition input unchanged.
    ScheduleTriggerResponse:
      type: object
      required:
      - runId
      - pipelineId
      - trigger
      properties:
        runId:
          type: integer
          format: int64
        pipelineId:
          type: integer
        trigger:
          type: string
          enum:
          - Manual
    ProblemDetails:
      type: object
      required:
      - title
      - status
      properties:
        type:
          type: string
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        traceId:
          type: string
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
    VersionInfo:
      type: object
      properties:
        version:
          type: string
          example: v0.5.0
        commit:
          type: string
        buildDate:
          type: string
        goVersion:
          type: string
        tier:
          type: string
          enum:
          - community
          - pro
          - enterprise
    LogRequest:
      type: object
      properties:
        message:
          type: string
          nullable: true
        logLevel:
          type: string
          example: INFO
          nullable: true
        created:
          type: string
          format: date-time
          nullable: true
        keywords:
          type: array
          items:
            "$ref": "#/components/schemas/PipelineKeyword"
        apiKey:
          type: string
          nullable: true
          writeOnly: true
          description: Optional legacy application attribution key in the body; see
            the operation description. It is not a header-auth requirement.
        id:
          type: integer
          nullable: true
          description: Compatibility field; ignored when storing a new log.
    LogResponse:
      type: object
      properties:
        id:
          type: integer
        applicationId:
          type: integer
        message:
          type: string
        logLevel:
          type: string
        created:
          type: string
          format: date-time
        keywords:
          type: array
          items:
            "$ref": "#/components/schemas/PipelineKeyword"
    WorkerBootstrapRequest:
      type: object
      required:
      - workerName
      properties:
        workerName:
          type: string
        instanceId:
          type: string
          description: Identity within the application. Rebootstrap reuses the worker
            record and replaces its token. Concurrent processes must not share an
            instanceId.
        workerVersion:
          type: string
        sdkVersion:
          type: string
        environment:
          type: string
        hostName:
          type: string
        pid:
          type: integer
        supportedHandlers:
          type: array
          items:
            type: string
        capabilities:
          type: object
          additionalProperties: true
        metadata:
          type: object
          additionalProperties: true
    WorkerBootstrapResponse:
      type: object
      properties:
        workerId:
          type: string
        workerSessionToken:
          type: string
          description: Session credential for lease, result, heartbeat, events, and
            shutdown. Result submission also requires the application API key. Default
            session TTL is 24 hours; heartbeat does not renew it.
        configVersion:
          type: string
        application:
          type: object
          properties:
            applicationId:
              type: integer
            applicationName:
              type: string
            appId:
              type: string
              description: Queue prefix for this application
              example: app_12
        messageBroker:
          type: object
          description: Included in bootstrap for all worker transports. HTTP workers
            ignore this object. connectionString is empty when WORKER_BROKER_HANDOUT=false.
          properties:
            type:
              type: string
              example: rabbitmq
            connectionString:
              type: string
            prefetch:
              type: integer
            topologyOwnership:
              type: string
              enum:
              - server-owned
              - client-owned
            dlqEnabled:
              type: boolean
            dlqTtlSec:
              type: integer
        queues:
          type: object
          properties:
            stageResult:
              type: string
            stageSetStatus:
              type: string
            stageUpdatedFanout:
              type: string
            stageNextPattern:
              type: string
              example: "{appId}_{handler}_StageNext"
              description: Substitute application.appId (for example app_12) and the
                stage handler name. This field is a literal pattern.
        heartbeat:
          type: object
          properties:
            intervalSec:
              type: integer
            offlineAfterSec:
              type: integer
        observability:
          type: object
          properties:
            traceLinkTemplate:
              type: string
            logsLinkTemplate:
              type: string
      required:
      - workerId
      - workerSessionToken
      - configVersion
      - application
      - messageBroker
      - queues
      - heartbeat
      - observability
    WorkerHeartbeatRequest:
      type: object
      required:
      - workerId
      properties:
        workerId:
          type: string
        state:
          type: string
          enum:
          - starting
          - ready
          - degraded
          - draining
          - stopped
          - error
          - offline
          description: Recognized states, normalized case-insensitively. Omitted or
            unrecognized values keep the previous state.
        uptimeSec:
          type: integer
        brokerConnected:
          type: boolean
        inFlightJobs:
          type: integer
        jobsProcessed:
          type: integer
        jobsFailed:
          type: integer
        queueLag:
          type: integer
        cpuPercent:
          type: number
        memoryMb:
          type: number
        lastError:
          type: string
        message:
          type: string
        metadata:
          type: object
          additionalProperties: true
    WorkerEventsRequest:
      type: object
      required:
      - workerId
      - events
      properties:
        workerId:
          type: string
        events:
          type: array
          items:
            type: object
            properties:
              ts:
                type: string
                format: date-time
                description: Defaults to server receive time when omitted.
              level:
                type: string
                enum:
                - TRACE
                - DEBUG
                - INFO
                - WARN
                - WARNING
                - ERROR
                default: INFO
                description: Case-insensitive. WARNING normalizes to WARN; omitted
                  or unrecognized levels normalize to INFO.
              eventType:
                type: string
                example: worker.state_changed
                default: worker.event
              message:
                type: string
                default: worker event
              details:
                type: object
                additionalProperties: true
          minItems: 1
          description: Nonempty batch; the configurable WORKER_EVENTS_MAX_BATCH limit
            defaults to 200.
    WorkerShutdownRequest:
      type: object
      required:
      - workerId
      properties:
        workerId:
          type: string
        reason:
          type: string
    WorkerAppendedStage:
      type: object
      required:
      - stageName
      - stageHandlerName
      properties:
        stageName:
          type: string
          minLength: 1
          maxLength: 255
        stageHandlerName:
          type: string
          minLength: 1
          maxLength: 300
        description:
          type: string
          maxLength: 255
        input:
          type: string
          description: String stage input. This worker-result path is subject to the
            complete result-request body cap; it does not perform the idempotent-create
            per-stage input check.
        options:
          "$ref": "#/components/schemas/StageOptions"
        isEvent:
          type: boolean
        stageId:
          type: integer
          nullable: true
          description: Compatibility field; ignored.
        pipelineId:
          type: integer
          nullable: true
          description: Compatibility field; ignored.
      description: Stage dynamically appended by a worker result. The current consumer
        inserts new stages and ignores supplied stageId/pipelineId. Input must be
        a string; inline policies and top-level continuation aliases are not consumed
        here.
    StageNextMessage:
      type: object
      required:
      - appId
      - stageId
      properties:
        appId:
          type: integer
          description: Numeric application ID; distinct from the bootstrap queue-prefix
            string application.appId.
        stageId:
          type: integer
        pipelineId:
          type: integer
        executionId:
          type: string
          description: Opaque current execution identity; preserve for lease and result
            operations.
        attempt:
          type: integer
          description: Current execution attempt; preserve in results.
        idempotencyKey:
          type: string
        timeoutSeconds:
          type: integer
        traceId:
          type: string
        spanId:
          type: string
        traceparent:
          type: string
        tracestate:
          type: string
        stageHandlerName:
          type: string
        input:
          type: string
        prevStageOutput:
          type: string
        contextItems:
          type: array
          items:
            "$ref": "#/components/schemas/ContextItem"
