openapi: 3.1.0
info:
  title: HEART API
  version: 1.0.0-draft
  summary: Standard access API for HEART-Embedded Systems (HTTP binding).
  description: Normative text is in HEART-API-Standard-1.0.md. Each operation states
    the lowest conformance level that must implement it in x-heart-level. Operations
    above a system's level return 501 with code not-implemented. Optional modules
    are marked module-<name> in x-heart-level. Operations in a module the system does
    not list in card.modules return 501. Every view above public needs scope heart.read;
    without it a caller gets the public view (API Standard 8.2). Every POST, PUT and
    PATCH whose x-heart-risk is not read needs an Idempotency-Key, and may answer
    202 with an Action awaiting approval.
  license:
    name: To be decided by the author
    identifier: LicenseRef-TBD
servers:
- url: https://{host}:{port}
  description: HEART (43278) is the standard port and 7685 the fallback. 443 is for
    internet-facing deployments.
  variables:
    host:
      default: system.example
    port:
      default: '43278'
      enum:
      - '43278'
      - '7685'
      - '443'
tags:
- name: Discovery
  description: Who is this system and what can it do?
- name: Reconnaissance
  description: What is happening inside it?
- name: Tending
  description: Alerts, capabilities and actions.
- name: AI
  description: Provider-neutral reasoning.
- name: Circulation
  description: System-to-system exchange.
- name: Valve
  description: Proof of what left the system.
- name: Evolving
  description: Model pins and adoption.
- name: Gateway
  description: One port, many systems. Routes by system ID.
- name: Management
  description: Configuration, lifecycle, software and files.
- name: Security
  description: Keys, attestation and audit.
- name: Custom
  description: Product-specific commands mapped to native protocols.
- name: Core
  description: The embedded AI runtime.
security:
- {}
- oauth2: []
- mtls: []
paths:
  /.well-known/heart-card.json:
    get:
      operationId: discoverCard
      tags:
      - Discovery
      summary: Public HEART Card
      description: Always public view. Must not require authentication.
      x-heart-level: basic
      security:
      - {}
      responses:
        '200':
          $ref: '#/components/responses/CardMessage'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/card:
    get:
      operationId: getCard
      tags:
      - Discovery
      summary: HEART Card at the caller's clearance
      x-heart-level: connected
      responses:
        '200':
          $ref: '#/components/responses/CardMessage'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/pulse:
    get:
      operationId: getPulse
      tags:
      - Reconnaissance
      summary: Current Pulse
      description: Returns 200 even when the system is failing. The status is in the
        Pulse.
      x-heart-level: basic
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/rhythm:
    get:
      operationId: getRhythm
      tags:
      - Reconnaissance
      summary: Event history, or a live stream
      description: 'Returns a page by default. With Accept text/event-stream it streams
        envelopes as Server-Sent Events and honours Last-Event-ID.

        '
      x-heart-level: connected
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: category
        in: query
        schema:
          type: string
      - $ref: '#/components/parameters/minSeverity'
      - name: since
        in: query
        schema:
          type: string
          format: date-time
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Page or event stream.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/page.schema.json
            text/event-stream:
              schema:
                type: string
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/arrhythmias:
    get:
      operationId: listArrhythmias
      tags:
      - Tending
      summary: List alerts
      x-heart-level: basic
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: status
        in: query
        schema:
          type: string
          enum:
          - open
          - acknowledged
          - tending
          - escalated
          - resolved
      - $ref: '#/components/parameters/minSeverity'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    post:
      operationId: postArrhythmias
      tags:
      - Tending
      summary: Report a problem to the system
      x-heart-level: connected
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - code
              - severity
              - summary
              additionalProperties: false
              properties:
                code:
                  type: string
                  description: Fault code (Part 3), profile code or reverse-DNS product
                    code.
                severity:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/severity
                summary:
                  type: string
                  maxLength: 200
                explanation:
                  type: string
                  maxLength: 2000
                component:
                  type: string
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/arrhythmias/{id}:
    parameters:
    - $ref: '#/components/parameters/id'
    get:
      operationId: getArrhythmia
      tags:
      - Tending
      summary: Get one alert
      x-heart-level: basic
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/arrhythmias/{id}/acknowledge:
    parameters:
    - $ref: '#/components/parameters/id'
    post:
      operationId: acknowledgeArrhythmia
      tags:
      - Tending
      summary: Acknowledge an alert
      description: Idempotent. Needs scope heart.tend.
      x-heart-level: connected
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              required: []
              additionalProperties: false
              properties:
                note: &id001
                  type: string
                  maxLength: 2000
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/capabilities/{name}/invoke:
    parameters:
    - name: name
      in: path
      required: true
      schema:
        $ref: ../schemas/1.0/common.schema.json#/$defs/capabilityName
    post:
      operationId: invokeCapability
      tags:
      - Tending
      summary: Invoke a capability
      description: Risk is the capability's. Returns 200 with a finished Action, or
        202 when the Action is running or awaiting approval. actionId names the Action,
        so a person can send presence for its digest in the same request; a destructive
        or physical capability then runs at once. A reused actionId gets 409 conflict
        (API Standard 6.3).
      x-heart-level: full
      security:
      - oauth2:
        - heart.invoke
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/invoke-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll the Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: per-item
  /heart/v1/actions:
    get:
      operationId: listActions
      tags:
      - Tending
      summary: List actions
      x-heart-level: basic
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: status
        in: query
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/actions/{id}:
    parameters:
    - $ref: '#/components/parameters/id'
    get:
      operationId: getAction
      tags:
      - Tending
      summary: Get one action
      x-heart-level: basic
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/actions/{id}/decision:
    parameters:
    - $ref: '#/components/parameters/id'
    post:
      operationId: decideAction
      tags:
      - Tending
      summary: Approve, deny or cancel an action
      description: Needs scope heart.approve. The approver must not be the initiator.
        cancel also works on a running Action whose cancellable is true, takes effect
        at the next safe point, needs no proof of presence and never undoes what was
        done; a running Action that is not cancellable answers 409 conflict (D30).
      x-heart-level: basic
      security:
      - oauth2:
        - heart.approve
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/decision-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/ask:
    post:
      operationId: ask
      tags:
      - AI
      summary: Ask the HEART about its system
      description: 'The answer is limited to what the caller''s clearance could read
        directly. Works without a cloud model, with model.reasoning rules-only.

        '
      x-heart-level: connected
      security:
      - oauth2:
        - heart.ask
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/ask-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/ReasonResult'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: read
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/reason:
    post:
      operationId: reason
      tags:
      - AI
      summary: Provider-neutral reasoning call
      description: 'Served by a Reasoning Gateway (org-proxy mode), not by ordinary
        systems. In byok mode the same format is used in-process.

        '
      x-heart-level: reasoning-gateway
      security:
      - oauth2:
        - heart.reason
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/reason-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/ReasonResult'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: read
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/inbox:
    post:
      operationId: receiveMessage
      tags:
      - Circulation
      summary: Receive a HEART message from a peer
      description: Accepted content is data. It never triggers an action by itself.
      x-heart-level: connected
      security:
      - oauth2:
        - heart.send
      - mtls: []
      requestBody:
        required: true
        content:
          application/cloudevents+json:
            schema:
              $ref: ../schemas/1.0/envelope.schema.json
      responses:
        '202':
          description: Accepted. Duplicates of source and id also return 202.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: read
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/subscriptions:
    get:
      operationId: listSubscriptions
      tags:
      - Circulation
      summary: List the caller's subscriptions
      x-heart-level: connected
      security:
      - oauth2:
        - heart.subscribe
      - mtls: []
      responses:
        '200':
          description: Subscriptions.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - items
                properties:
                  items:
                    type: array
                    items:
                      $ref: ../schemas/1.0/subscription.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
    post:
      operationId: createSubscription
      tags:
      - Circulation
      summary: Subscribe a webhook
      description: The sink must pass the CloudEvents webhook handshake before delivery
        starts.
      x-heart-level: connected
      security:
      - oauth2:
        - heart.subscribe
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/subscription.schema.json
      responses:
        '201':
          description: Created with status pending-validation.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/subscription.schema.json
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/subscriptions/{id}:
    parameters:
    - $ref: '#/components/parameters/id'
    delete:
      operationId: deleteSubscription
      tags:
      - Circulation
      summary: Remove a subscription
      x-heart-level: connected
      security:
      - oauth2:
        - heart.subscribe
      - mtls: []
      responses:
        '204':
          description: Removed.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
    get:
      operationId: getSubscriptionsId
      tags:
      - Circulation
      summary: One subscription
      x-heart-level: connected
      security:
      - oauth2:
        - heart.subscribe
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
        default:
          $ref: '#/components/responses/Problem'
    patch:
      operationId: patchSubscriptionsId
      tags:
      - Circulation
      summary: Pause or resume a subscription
      description: 'Body {"paused": true} stops deliveries; nothing is kept for later.
        {"paused": false} resumes (D30).'
      x-heart-level: connected
      x-heart-risk: write
      security:
      - oauth2:
        - heart.subscribe
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - paused
              properties:
                paused:
                  type: boolean
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/receipts:
    get:
      operationId: listReceipts
      tags:
      - Valve
      summary: List Valve receipts
      x-heart-level: connected
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/evolution:
    get:
      operationId: getEvolution
      tags:
      - Evolving
      summary: Model pins, candidates and regression results
      x-heart-level: full
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/systems:
    get:
      operationId: listSystems
      tags:
      - Gateway
      summary: Every hosted system's HEART Card
      description: 'HEART Gateway only. Each item is a heart.card message at the caller''s
        clearance. For each hosted system the Gateway also serves the API above under
        /heart/v1/systems/{ref}/, where ref is the systemId or its alias, for example
        /heart/v1/systems/pitch-lab/pulse.

        '
      x-heart-level: heart-gateway
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/capabilities:
    get:
      operationId: getCapabilities
      tags:
      - Tending
      summary: Search capabilities (q, kind, risk)
      x-heart-level: connected
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: q
        in: query
        description: Words to search for in name, title and description.
        schema:
          type: string
          maxLength: 200
      - name: kind
        in: query
        schema:
          enum:
          - standard
          - product
          - custom
      - name: risk
        in: query
        schema:
          enum:
          - read
          - write
          - destructive
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - items
                properties:
                  items:
                    type: array
                    items:
                      $ref: ../schemas/1.0/card.schema.json#/$defs/capability
                  nextCursor:
                    type:
                    - string
                    - 'null'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/capabilities/{name}:
    get:
      operationId: getCapabilitiesName
      tags:
      - Tending
      summary: One capability
      x-heart-level: connected
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/card.schema.json#/$defs/capability
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/arrhythmias/{id}/resolve:
    post:
      operationId: postArrhythmiasIdResolve
      tags:
      - Tending
      summary: Mark an alert resolved
      x-heart-level: connected
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              required: []
              additionalProperties: false
              properties:
                note: *id001
  /heart/v1/arrhythmias/{id}/silence:
    post:
      operationId: postArrhythmiasIdSilence
      tags:
      - Tending
      summary: Silence repeats of an alert for a period
      x-heart-level: connected
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      x-heart-risk: write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              description: Give silencedUntil (at most 30 days ahead) or durationSec.
                The silence covers the alert's code. Alerts with that code are still
                raised and listed, each with silencedUntil, but are not notified.
              properties:
                silencedUntil:
                  type: string
                  format: date-time
                durationSec:
                  type: integer
                  minimum: 60
                  maximum: 2592000
                note: *id001
              oneOf:
              - required:
                - silencedUntil
              - required:
                - durationSec
    delete:
      operationId: deleteArrhythmiasIdSilence
      tags:
      - Tending
      summary: End a silence early
      description: Alerts with this code are notified again at once, and silencedUntil is removed from them.
      x-heart-level: connected
      x-heart-risk: write
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/components:
    get:
      operationId: getComponents
      tags:
      - Reconnaissance
      summary: Everything inside the system, as a tree
      x-heart-level: module-inventory
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/components/{id}:
    get:
      operationId: getComponentsId
      tags:
      - Reconnaissance
      summary: One component and its status
      x-heart-level: module-inventory
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          maxLength: 200
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/dependencies:
    get:
      operationId: getDependencies
      tags:
      - Reconnaissance
      summary: External services and systems it relies on
      x-heart-level: module-inventory
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/properties:
    get:
      operationId: getProperties
      tags:
      - Reconnaissance
      summary: All readable values
      x-heart-level: module-properties
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/properties/{name}:
    get:
      operationId: getPropertiesName
      tags:
      - Reconnaissance
      summary: Read one value, or stream it
      x-heart-level: module-properties
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    put:
      operationId: putPropertiesName
      tags:
      - Reconnaissance
      summary: Write one value
      x-heart-level: module-properties
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - value
              additionalProperties: false
              properties:
                value: {}
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: &id002
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      description: Write, and physical when the property is. A person writing a physical
        property sends actionId and presence to run it at once; without them the write
        waits as an Action for another person's approval (API Standard 6.3).
  /heart/v1/config:
    get:
      operationId: getConfig
      tags:
      - Management
      summary: Current configuration
      x-heart-level: module-config
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
    patch:
      operationId: patchConfig
      tags:
      - Management
      summary: Change settings (JSON Merge Patch)
      x-heart-level: module-config
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      requestBody:
        required: true
        content:
          application/merge-patch+json:
            schema:
              type: object
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/config/validate:
    post:
      operationId: postConfigValidate
      tags:
      - Management
      summary: Check settings without applying them
      x-heart-level: module-config
      x-heart-risk: read
      description: Takes the same merge patch as PATCH /heart/v1/config and changes nothing.
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - valid
                - errors
                properties:
                  valid:
                    type: boolean
                  revision:
                    type: integer
                    minimum: 0
                    description: The revision the patch was checked against.
                  errors:
                    type: array
                    items:
                      type: object
                      required:
                      - setting
                      - code
                      properties:
                        setting:
                          type: string
                        code:
                          type: string
                          description: The problem code the same PATCH would answer.
                        detail:
                          type: string
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/config/history:
    get:
      operationId: getConfigHistory
      tags:
      - Management
      summary: Earlier revisions
      x-heart-level: module-config
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/config/rollback:
    post:
      operationId: postConfigRollback
      tags:
      - Management
      summary: Return to an earlier revision
      x-heart-level: module-config
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - revision
              properties:
                revision:
                  type: integer
                  minimum: 0
                  description: The revision whose values are applied again, as a new revision.
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/metrics:
    get:
      operationId: getMetrics
      tags:
      - Reconnaissance
      summary: List metrics
      x-heart-level: module-telemetry
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/metrics/{name}:
    get:
      operationId: getMetricsName
      tags:
      - Reconnaissance
      summary: Time series (from, to, step)
      x-heart-level: module-telemetry
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      - name: from
        in: query
        schema:
          type: string
          format: date-time
      - name: to
        in: query
        schema:
          type: string
          format: date-time
      - name: step
        in: query
        description: Seconds between points.
        schema:
          type: integer
          minimum: 1
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/logs:
    get:
      operationId: getLogs
      tags:
      - Reconnaissance
      summary: Read or stream logs
      x-heart-level: module-telemetry
      description: Oldest first. With Accept text/event-stream, new entries are streamed as for the Rhythm.
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: since
        in: query
        schema:
          type: string
          format: date-time
      - name: until
        in: query
        schema:
          type: string
          format: date-time
      - $ref: '#/components/parameters/minSeverity'
      - name: component
        in: query
        schema:
          type: string
          maxLength: 200
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/diagnostics:
    get:
      operationId: getDiagnostics
      tags:
      - Management
      summary: Available tests and past runs
      x-heart-level: module-diagnostics
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/diagnostics/bundle:
    post:
      operationId: postDiagnosticsBundle
      tags:
      - Management
      summary: Build a support bundle
      x-heart-level: module-diagnostics
      x-heart-risk: read
      security:
      - oauth2:
        - heart.operate
      - mtls: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                since:
                  type: string
                  format: date-time
                until:
                  type: string
                  format: date-time
                include:
                  type: array
                  items:
                    enum:
                    - logs
                    - rhythm
                    - config
                    - components
                    - diagnostics
                    - metrics
                    - pulse
                maxBytes:
                  type: integer
                  minimum: 1024
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/diagnostics/{test}:
    post:
      operationId: postDiagnosticsTest
      tags:
      - Management
      summary: Run a self-test
      x-heart-level: module-diagnostics
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.operate
      - mtls: []
      parameters:
      - name: test
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      description: write if the test is disruptive, otherwise read.
  /heart/v1/lifecycle:
    get:
      operationId: getLifecycle
      tags:
      - Management
      summary: Current phase and allowed operations
      x-heart-level: module-lifecycle
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/lifecycle/{operation}:
    post:
      operationId: postLifecycleOperation
      tags:
      - Management
      summary: restart, shutdown, sleep, wake, drain, reload, power-cycle, safe-mode,
        maintenance-on, maintenance-off, partial resets, factory-reset, decommission
      x-heart-level: module-lifecycle
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.operate
      - mtls: []
      parameters:
      - name: operation
        in: path
        required: true
        schema:
          anyOf:
          - enum:
            - restart
            - shutdown
            - sleep
            - wake
            - drain
            - reload
            - power-cycle
            - safe-mode
            - maintenance-on
            - maintenance-off
            - reset-config
            - reset-network
            - clear-data
            - factory-reset
            - decommission
          - type: string
            pattern: ^x-[a-z0-9][a-z0-9-]*$
        description: A standard operation, or a vendor operation starting with x-.
          Any other name answers 404 not-found; a standard one the system does not
          offer (card.lifecycle.operations) answers 501 not-implemented.
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/lifecycle-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '201':
          description: 'Created: with delaySec above 0, the heart.schedule that carries the request out later (13.2 rule 3.7).'
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      description: 'Risk per request (API Standard 13.2 rule 3, D29): restart (graceful),
        shutdown, sleep, wake, drain, reload, safe-mode and maintenance-off are write;
        restart with mode force, power-cycle, maintenance-on, reset-config, reset-network,
        clear-data, factory-reset and decommission are destructive; shutdown is destructive
        when card.lifecycle.wakeSources is none or only local. An option can only
        raise the risk. The answer is the Action; shutdown, sleep, restart and power-cycle
        Actions carry nextReachableAt.'
  /heart/v1/software:
    get:
      operationId: getSoftware
      tags:
      - Management
      summary: Installed software and firmware
      x-heart-level: module-software
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/software/sbom:
    get:
      operationId: getSoftwareSbom
      tags:
      - Management
      summary: Software bill of materials (SPDX or CycloneDX)
      description: The SBOM document as the system holds it, SPDX or CycloneDX
        JSON. It is internal, so a caller below that clearance gets 403 insufficient-clearance.
        A system without one answers 404 not-found.
      x-heart-level: module-software
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/software/updates:
    get:
      operationId: getSoftwareUpdates
      tags:
      - Management
      summary: Available updates, update channel and policy
      description: Answers a heart.software message with packages, channel, available
        and updatePolicy. Each available update says whether its manifest is signed
        by a key the system trusts.
      x-heart-level: module-software
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
    post:
      operationId: postSoftwareUpdates
      tags:
      - Management
      summary: Start a signed update
      description: 'Installs one available update (API Standard 13.2 rule 4). Installing
        changes what runs, so it is destructive. The answer is the Action, whose result
        is the heart.update. Unknown version: 404 not-found. A manifest or payload
        the system cannot verify: 403 signature-invalid, and nothing is installed.
        An update already running, or the version already installed: 409 conflict.'
      x-heart-level: module-software
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.operate
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - version
              properties:
                version:
                  type: string
                  minLength: 1
                  maxLength: 64
                  description: The version to install, as listed by GET /software/updates.
                package:
                  type: string
                  description: The package it updates, when the system has more than one.
                sha256:
                  type: string
                  pattern: ^[a-f0-9]{64}$
                  description: The payload digest the caller expects. A different one
                    is refused with 409 conflict.
                reason:
                  type: string
                  maxLength: 500
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/software/updates/{id}:
    get:
      operationId: getSoftwareUpdatesId
      tags:
      - Management
      summary: Update progress
      x-heart-level: module-software
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/software/rollback:
    post:
      operationId: postSoftwareRollback
      tags:
      - Management
      summary: Return to the previous version
      description: Returns to the version that ran before the last update. That version
        was approved when it was installed, so this is write. No earlier version
        kept, or an update running, answers 409 conflict. The answer is a heart.update,
        or the Action whose result it is.
      x-heart-level: module-software
      x-heart-risk: write
      security:
      - oauth2:
        - heart.operate
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                reason:
                  type: string
                  maxLength: 500
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/artifacts:
    get:
      operationId: getArtifacts
      tags:
      - Management
      summary: List stored files
      x-heart-level: module-artifacts
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    post:
      operationId: postArtifacts
      tags:
      - Management
      summary: Upload a file
      description: 'Stores one file, sent as base64 in content. The answer is the
        heart.artifact. privacy is the level of the file''s content: at most the
        caller''s clearance, never never-share. A sha256 that does not match the
        content answers 400 invalid-request; a full store answers 409 conflict.'
      x-heart-level: module-artifacts
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - kind
              - content
              properties:
                kind:
                  $ref: ../schemas/1.0/artifact.schema.json#/properties/kind
                privacy:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/messageLevel
                mediaType:
                  type: string
                  maxLength: 255
                  pattern: ^[A-Za-z0-9!#$&^_.+-]+/[A-Za-z0-9!#$&^_.+-]+$
                content:
                  type: string
                  contentEncoding: base64
                  description: The file, base64 (RFC 4648 section 4).
                sha256:
                  type: string
                  pattern: ^[a-f0-9]{64}$
                expiresAt:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/timestamp
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '201':
          description: 'Created: the stored heart.artifact, with Location.'
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/artifacts/{id}:
    get:
      operationId: getArtifactsId
      tags:
      - Management
      summary: File details
      x-heart-level: module-artifacts
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    delete:
      operationId: deleteArtifactsId
      tags:
      - Management
      summary: Delete a file
      x-heart-level: module-artifacts
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/artifacts/{id}/content:
    get:
      operationId: getArtifactsIdContent
      tags:
      - Management
      summary: Download, with HTTP range support
      description: The file's bytes, with its mediaType as Content-Type and its sha256
        as ETag. A caller below the file's privacy level gets 404 not-found, as for
        a file that does not exist. One byte range (RFC 9110 Range) answers 206.
      x-heart-level: module-artifacts
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      - name: Range
        in: header
        required: false
        schema:
          type: string
          pattern: ^bytes=[0-9]*-[0-9]*$
      responses:
        '200':
          description: File content.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
            ETag:
              schema:
                type: string
            Accept-Ranges:
              schema:
                type: string
          content:
            application/octet-stream:
              schema:
                type: string
                contentMediaType: application/octet-stream
        '206':
          description: Partial content.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
            Content-Range:
              schema:
                type: string
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/schedules:
    get:
      operationId: getSchedules
      tags:
      - Management
      summary: List schedules and maintenance windows
      x-heart-level: module-schedules
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    post:
      operationId: postSchedules
      tags:
      - Management
      summary: Schedule any operation for later
      description: 'Creates a schedule (API Standard 6.3 and 13.2 rule 17). Its risk
        is that of the operation it schedules, at least write, and destructive for
        a maintenance window. The allowlist never covers it. The answer is the heart.schedule
        (201), or the Action whose result it is.'
      x-heart-level: module-schedules
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
              - kind
              properties:
                kind:
                  $ref: ../schemas/1.0/schedule.schema.json#/properties/kind
                enabled:
                  type: boolean
                at:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/timestamp
                cron:
                  $ref: ../schemas/1.0/schedule.schema.json#/properties/cron
                timezone:
                  type: string
                durationSec:
                  type: integer
                  minimum: 1
                operation:
                  $ref: ../schemas/1.0/schedule.schema.json#/properties/operation
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '201':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/schedules/{id}:
    get:
      operationId: getSchedulesId
      tags:
      - Management
      summary: One schedule
      x-heart-level: module-schedules
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    delete:
      operationId: deleteSchedulesId
      tags:
      - Management
      summary: Remove a schedule
      x-heart-level: module-schedules
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/tending/autonomy:
    get:
      operationId: getTendingAutonomy
      tags:
      - Tending
      summary: 'Autonomy now: the ceiling a person set, the current level and the mode that follows from it'
      x-heart-level: module-control
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
    put:
      operationId: putTendingAutonomy
      tags:
      - Tending
      summary: Set the autonomy ceiling, 0 to 5
      x-heart-level: module-control
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - max
              additionalProperties: false
              properties:
                max:
                  type: integer
                  minimum: 0
                  maximum: 5
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      description: 'Lowering max needs only heart.tend and no approval; lowering it
        to 2 or below is Stop, with exactly the effects of POST /heart/v1/tending/stop
        (API Standard 13.4). Raising max is destructive, needs heart.admin and may
        come only from a person: the person sends actionId and presence to raise it
        in one call, or it waits for another person''s approval (API Standard 6.3).
        The mode is never set: it follows from the current level.'
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/tending/allowlist:
    put:
      operationId: putTendingAllowlist
      tags:
      - Tending
      summary: Replace the allowlist of write actions that may run without asking
      description: Adding or widening an entry is destructive; removing or narrowing
        is write (API Standard 6.3, 13.2).
      x-heart-level: module-control
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - allowlist
              additionalProperties: false
              properties:
                allowlist:
                  $ref: ../schemas/1.0/control.schema.json#/properties/allowlist
                reason:
                  type: string
                  maxLength: 2000
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/tending/stop:
    post:
      operationId: postTendingStop
      tags:
      - Tending
      summary: Stop all autonomous action at once
      x-heart-level: module-control
      x-heart-risk: read
      security:
      - oauth2:
        - heart.tend
      - mtls: []
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
      description: 'Stop (API Standard 13.4): sets the autonomy ceiling max to 2
        (mode observe) at once, cancels every Action that has not started, cancels
        running cancellable ones at their next safe point, and undoes a running Trial.
        Needs no approval and no network. PUT /heart/v1/tending/autonomy with max
        2 or below is the same operation. Stop stops automatic action, not the machine:
        use a capability named halt for that.'
  /heart/v1/tending/rules:
    get:
      operationId: getTendingRules
      tags:
      - Tending
      summary: List Tending rules
      x-heart-level: module-control
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/tending/rules/{id}:
    put:
      operationId: putTendingRulesId
      tags:
      - Tending
      summary: Add or change a rule
      x-heart-level: module-control
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/rule.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
    delete:
      operationId: deleteTendingRulesId
      tags:
      - Tending
      summary: Remove a rule
      x-heart-level: module-control
      x-heart-risk: write
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/tending/proposals:
    post:
      operationId: postTendingProposals
      tags:
      - Tending
      summary: Deliver a brain's Proposal. It becomes an Action with initiator ai,
        which passes the gate (Core Standard 7.3).
      description: Records the Proposal and starts its Trial. The Core reads the current
        values itself before the first step. The change is a separate Action, gated
        like any other, so delivering changes nothing by itself. Never a /serve target
        (API Standard 13.2).
      x-heart-level: module-control
      x-heart-risk: write
      security:
      - oauth2:
        - heart.propose
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - proposal
              additionalProperties: false
              properties:
                proposal:
                  $ref: ../schemas/1.0/proposal.schema.json
      responses:
        '202':
          $ref: '#/components/responses/Accepted'
        '400':
          description: invalid-request
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/problem+json:
              schema:
                $ref: ../schemas/1.0/problem.schema.json
        '403':
          description: 'caller-not-allowed: the target''s callers lacks ai'
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/problem+json:
              schema:
                $ref: ../schemas/1.0/problem.schema.json
        '404':
          description: 'not-found: no such target'
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/problem+json:
              schema:
                $ref: ../schemas/1.0/problem.schema.json
        '409':
          description: conflict (a Trial is already running on the target; refused,
            not queued) or autonomy-stopped
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/problem+json:
              schema:
                $ref: ../schemas/1.0/problem.schema.json
        '422':
          description: out-of-range, or cannot-undo (destructive target, or current
            value unknown)
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/problem+json:
              schema:
                $ref: ../schemas/1.0/problem.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/tending/trials/{id}:
    get:
      operationId: getTendingTrialsId
      tags:
      - Tending
      summary: One Trial, as heart.trial (Core Standard 7.5)
      x-heart-level: module-control
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/valve/policy:
    get:
      operationId: getValvePolicy
      tags:
      - Valve
      summary: Current Valve policy
      x-heart-level: module-privacy
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
    put:
      operationId: putValvePolicy
      tags:
      - Valve
      summary: Change Valve policy
      x-heart-level: module-privacy
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: The whole new policy. A field left out takes its default
                (API Standard 13.2 rule 6).
              additionalProperties: false
              properties:
                llmCeiling:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/messageLevel
                classifications:
                  type: array
                  maxItems: 500
                  items:
                    $ref: ../schemas/1.0/card.schema.json#/$defs/classification
                retentionDays:
                  type: integer
                  minimum: 1
                  maximum: 36500
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/consents:
    get:
      operationId: getConsents
      tags:
      - Valve
      summary: List consents
      x-heart-level: module-privacy
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    post:
      operationId: postConsents
      tags:
      - Valve
      summary: Record a consent
      x-heart-level: module-privacy
      x-heart-risk: write
      security:
      - oauth2:
        - heart.data
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - purpose
              - recipient
              additionalProperties: false
              properties:
                purpose:
                  type: string
                  minLength: 1
                  maxLength: 200
                recipient:
                  type: string
                  minLength: 1
                  maxLength: 500
                  description: A kind of recipient (model-provider, subscriber, peer,
                    gateway) or one recipient's name.
                subject:
                  type: string
                  minLength: 3
                  maxLength: 200
                  description: The person who consents. By default the caller.
                expiresAt:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/timestamp
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/consents/{id}:
    delete:
      operationId: deleteConsentsId
      tags:
      - Valve
      summary: Withdraw a consent
      x-heart-level: module-privacy
      x-heart-risk: write
      security:
      - oauth2:
        - heart.data
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/data/export:
    post:
      operationId: postDataExport
      tags:
      - Valve
      summary: Export one person's data
      x-heart-level: module-privacy
      x-heart-risk: read
      security:
      - oauth2:
        - heart.data
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - subject
              - authority
              additionalProperties: false
              properties:
                subject:
                  type: string
                  minLength: 3
                  maxLength: 200
                  description: The identified person whose data is exported.
                authority:
                  type: string
                  minLength: 1
                  maxLength: 500
                  description: Proof of authority to act for that person (API Standard
                    13.2 rule 6).
                reason:
                  type: string
                  maxLength: 2000
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/data/erase:
    post:
      operationId: postDataErase
      tags:
      - Valve
      summary: Erase one person's data
      x-heart-level: module-privacy
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.data
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - subject
              - authority
              additionalProperties: false
              properties:
                subject:
                  type: string
                  description: The identified person whose data is erased.
                authority:
                  type: string
                  description: Proof of authority to act for that person (API Standard
                    13.2).
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/brain:
    get:
      operationId: getBrain
      tags:
      - AI
      summary: Whether it may consult a brain now, under which lease, and why not
      x-heart-level: module-brain
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/brain/signal:
    post:
      operationId: postBrainSignal
      tags:
      - AI
      summary: A signed signal from the Command Center that only lowers risk (brain-off,
        revoke-model, revoke-use, autonomy-stop)
      description: Needs no token and no approval. It is accepted only if it is signed
        with the pinned Command Center key, is for this system, is at most 300 seconds
        old and was not seen before (API Standard 7.4 rule 8). No signal can raise
        anything.
      x-heart-level: module-brain
      x-heart-risk: read
      security:
      - {}
      parameters:
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/brain-signal.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/brain/restore:
    post:
      operationId: postBrainRestore
      tags:
      - AI
      summary: The owner lets the brain come back after a cut; the next valid lease
        is then accepted
      description: Destructive, because it raises autonomy (Section 6.3). Only for
        a system with brain.restoreNeedsOwner; others accept the next valid lease
        by themselves. The owner sends actionId and presence to restore in one call
        (API Standard 6.3, rule 3).
      x-heart-level: module-brain
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Waits for proof of presence; poll Location.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        default:
          $ref: '#/components/responses/Problem'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
  /heart/v1/brain/offline:
    put:
      operationId: putBrainOffline
      tags:
      - AI
      summary: Turn auto mode on or off (a local model may go on, narrowing, while
        the link is lost)
      description: Turning it off only lowers risk and needs heart.tend. Turning
        it on is destructive (the owner, with proof of presence) and also needs heart.admin
        (API Standard 7.4 rule 10, 13.2 rule 12).
      x-heart-level: module-brain
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.tend
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/brain-offline-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Waits for proof of presence; poll Location.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/ai/policy:
    get:
      operationId: getAiPolicy
      tags:
      - AI
      summary: Providers, budgets and regions
      x-heart-level: module-ai
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
    put:
      operationId: putAiPolicy
      tags:
      - AI
      summary: Change them
      x-heart-level: module-ai
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: The whole new policy (API Standard 13.2 rule 18).
              additionalProperties: false
              properties:
                modes:
                  type: array
                  minItems: 1
                  items:
                    enum:
                    - byok
                    - org-proxy
                providers:
                  type: array
                  maxItems: 50
                  items:
                    type: string
                regions:
                  type: array
                  maxItems: 50
                  items:
                    type: string
                uses:
                  type: array
                  items:
                    enum:
                    - explain
                    - serve
                    - propose
                    - plan
                    - chat
                dailyBudgetUsd:
                  type: number
                  minimum: 0
                monthlyBudgetUsd:
                  type: number
                  minimum: 0
                maxCallUsd:
                  type: number
                  minimum: 0
                allowFallback:
                  type: boolean
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/ai/usage:
    get:
      operationId: getAiUsage
      tags:
      - AI
      summary: Calls, tokens and cost over time
      x-heart-level: module-ai
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/memory:
    get:
      operationId: getMemory
      tags:
      - AI
      summary: List stored memory
      x-heart-level: module-memory
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/memory/search:
    post:
      operationId: postMemorySearch
      tags:
      - AI
      summary: Search memory
      x-heart-level: module-memory
      x-heart-risk: read
      security:
      - oauth2:
        - heart.read
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - query
              additionalProperties: false
              properties:
                query:
                  type: string
                  minLength: 1
                  maxLength: 500
                scope:
                  enum:
                  - short-term
                  - long-term
                limit:
                  type: integer
                  minimum: 1
                  maximum: 100
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/memory/{id}:
    delete:
      operationId: deleteMemoryId
      tags:
      - AI
      summary: Forget one item
      x-heart-level: module-memory
      x-heart-risk: write
      security:
      - oauth2:
        - heart.data
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/evolution/pins/{purpose}:
    put:
      operationId: putEvolutionPinsPurpose
      tags:
      - Evolving
      summary: Pin a model for a purpose
      x-heart-level: module-evolving
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: purpose
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - provider
              - model
              additionalProperties: false
              properties:
                provider:
                  type: string
                model:
                  type: string
                version:
                  type: string
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/evolution/rollback:
    post:
      operationId: postEvolutionRollback
      tags:
      - Evolving
      summary: Return to the previous pin
      x-heart-level: module-evolving
      x-heart-risk: write
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                purpose:
                  type: string
                  description: By default the purpose changed last.
                reason:
                  type: string
                  maxLength: 2000
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/presence
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/evolution/lessons:
    get:
      operationId: getEvolutionLessons
      tags:
      - Evolving
      summary: What it has learned from incidents
      x-heart-level: module-evolving
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/feedback:
    post:
      operationId: postFeedback
      tags:
      - Evolving
      summary: Rate an answer or action
      x-heart-level: module-evolving
      x-heart-risk: read
      security:
      - oauth2:
        - heart.ask
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - about
              - id
              - rating
              additionalProperties: false
              properties:
                about:
                  enum:
                  - action
                  - answer
                  - trial
                  - lesson
                id:
                  type: string
                  description: The Action, Trial or lesson ID, or the receiptId of
                    an answer from /ask.
                rating:
                  type: integer
                  minimum: 1
                  maximum: 5
                comment:
                  type: string
                  maxLength: 2000
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/security:
    get:
      operationId: getSecurity
      tags:
      - Security
      summary: Certificates, keys and boot state
      x-heart-level: module-security
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/security/attestation:
    get:
      operationId: getSecurityAttestation
      tags:
      - Security
      summary: Evidence of what is running (RFC 9334)
      description: A compact JWS signed by the identity key over the caller's nonce
        and what is running (API Standard 13.2 rule 7). Needs internal clearance.
      x-heart-level: module-security
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - name: nonce
        in: query
        required: true
        description: Chosen by the caller, so the evidence is fresh.
        schema:
          type: string
          minLength: 8
          maxLength: 128
      - $ref: '#/components/parameters/dpop'
  /heart/v1/security/rotate:
    post:
      operationId: postSecurityRotate
      tags:
      - Security
      summary: Rotate the identity key
      description: Publishes a rotation statement signed with the old key (API
        Standard 10.1 rule 7). Destructive, because it changes whom every peer trusts.
      x-heart-level: module-security
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                key:
                  enum:
                  - identity
                  default: identity
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/audit:
    get:
      operationId: getAudit
      tags:
      - Security
      summary: Tamper-evident audit log
      x-heart-level: module-security
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - name: category
        in: query
        schema:
          $ref: ../schemas/1.0/audit.schema.json#/properties/category
      - name: outcome
        in: query
        schema:
          $ref: ../schemas/1.0/audit.schema.json#/properties/outcome
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/presence/methods:
    get:
      operationId: getPresenceMethods
      tags:
      - Security
      summary: Enrolled ways to prove presence, without key material
      x-heart-level: module-presence
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Methods, internal.
          headers:
            Heart-Version: &id003
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - items
                properties:
                  items:
                    type: array
                    items:
                      $ref: ../schemas/1.0/presence-method.schema.json
                  nextCursor:
                    type:
                    - string
                    - 'null'
        default:
          $ref: '#/components/responses/Problem'
    post:
      operationId: postPresenceMethods
      tags:
      - Security
      summary: Enrol a passkey or a CIBA device for the calling person
      description: 'Destructive: it grants the power to approve (API Standard 6.3,
        13.2 rule 13). Proved by one of the caller''s own methods, in the same request
        (actionId and presence), or by another person''s approval. While the system
        has no method at all, the first is proved by presence at the device: the request
        comes through the local interface, or is confirmed on the device.'
      x-heart-level: module-presence
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/presence-method.schema.json
      responses:
        '201':
          description: Enrolled.
          headers:
            Heart-Version: *id003
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/presence-method.schema.json
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/presence/methods/{id}:
    parameters:
    - $ref: '#/components/parameters/id'
    delete:
      operationId: deletePresenceMethodsId
      tags:
      - Security
      summary: Remove a way to prove presence
      description: 'Write: removing only lowers authority, so it needs no proof. 409
        conflict for the last method of a system with card.presence.requireMethod,
        and for a method set in the system''s configuration (API Standard 13.2 rule
        13).'
      x-heart-level: module-presence
      x-heart-risk: write
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Removed.
          headers:
            Heart-Version: *id003
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/platform:
    get:
      operationId: getPlatform
      tags:
      - Reconnaissance
      summary: Hardware, OS, power, network and clock
      x-heart-level: module-platform
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/provisioning/claim:
    post:
      operationId: postProvisioningClaim
      tags:
      - Management
      summary: First-time claim by an owner
      x-heart-level: module-provisioning
      x-heart-risk: destructive
      security:
      - {}
      description: Authorised by a one-time claim token in the body, not by a caller
        identity.
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - claimToken
              - ownerKey
              additionalProperties: false
              properties:
                claimToken:
                  type: string
                  minLength: 16
                  maxLength: 200
                  description: The one-time code supplied with the device (API Standard
                    10.1).
                ownerKey:
                  type: object
                  description: The owner's public JWK, recorded as the owner's authority.
                issuer:
                  type: string
                  format: uri
                  description: The owner's token issuer, becomes card.auth.issuer.
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/provisioning/transfer:
    post:
      operationId: postProvisioningTransfer
      tags:
      - Management
      summary: Transfer to a new owner
      x-heart-level: module-provisioning
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - newOwnerKey
              - presence
              additionalProperties: false
              properties:
                newOwnerKey:
                  type: object
                issuer:
                  type: string
                  format: uri
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/provisioning/release:
    post:
      operationId: postProvisioningRelease
      tags:
      - Management
      summary: Give the system up without naming a new owner
      description: 'Destructive, with the owner''s proof of presence in the request
        (actionId and presence). It removes the owner, every presence method, grant,
        subscription, consent and schedule, and cancels the Actions waiting for approval.
        The system then makes a new claim code, shown only at the device, and can be
        claimed again. Personal data stays until it is erased (API Standard 13.2 rule
        8).'
      x-heart-level: module-provisioning
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - presence
              additionalProperties: false
              properties:
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/access/grants:
    get:
      operationId: getAccessGrants
      tags:
      - Security
      summary: Who may call the system, and with which client certificate
      description: Each grant as a heart.grant, filtered for the caller's clearance
        (API Standard 13.2 rule 21). Needs a human caller.
      x-heart-level: module-access
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          description: Grants, newest last.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - items
                properties:
                  items:
                    type: array
                    items:
                      $ref: ../schemas/1.0/envelope.schema.json
                  nextCursor:
                    type:
                    - string
                    - 'null'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/access/grants/{principal}:
    parameters:
    - name: principal
      in: path
      required: true
      description: The sub of the principal's tokens.
      schema:
        type: string
        pattern: ^[A-Za-z0-9._:@+=~-]{1,256}$
    put:
      operationId: putAccessGrantsPrincipal
      tags:
      - Security
      summary: Give a principal a role, or change its grant
      description: 'A new grant, a role with more scopes or a higher clearance, a more
        powerful caller kind, a new certificate, or a later or removed expiry widens
        authority, so it is destructive (API Standard 6.3); any other change is write.
        The first grant gives the owner role; the last owner grant keeps it (409 conflict).
        Needs a human caller (13.2 rule 21).'
      x-heart-level: module-access
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/grant.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '201':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
    delete:
      operationId: deleteAccessGrantsPrincipal
      tags:
      - Security
      summary: Remove a principal's grant
      description: 'Write: removing only lowers authority. The last owner grant cannot
        be removed (409 conflict); releasing or transferring the system removes it (API
        Standard 13.2 rule 21).'
      x-heart-level: module-access
      x-heart-risk: write
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Removed.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/peers:
    get:
      operationId: getPeers
      tags:
      - Circulation
      summary: Known peers and their trust
      x-heart-level: module-peers
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/peers/{id}:
    put:
      operationId: putPeersId
      tags:
      - Circulation
      summary: Trust a peer or set its clearance
      x-heart-level: module-peers
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - trust
              additionalProperties: false
              properties:
                trust:
                  enum:
                  - pending
                  - trusted
                  - blocked
                clearance:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/messageLevel
                types:
                  $ref: ../schemas/1.0/peer.schema.json#/properties/types
                reason: *id001
                actionId:
                  $ref: ../schemas/1.0/common.schema.json#/$defs/actionId
                presence: *id002
              dependentRequired:
                presence:
                - actionId
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
    delete:
      operationId: deletePeersId
      tags:
      - Circulation
      summary: Remove a peer
      x-heart-level: module-peers
      x-heart-risk: write
      security:
      - oauth2:
        - heart.admin
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: id
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/batch:
    post:
      operationId: postBatch
      tags:
      - Circulation
      summary: Several operations in one call
      x-heart-level: module-batch
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/batch-request.schema.json
      responses:
        '200':
          description: One result per item run, in order (API Standard 13.2 rule 9).
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
                required:
                - results
                - stopped
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      required:
                      - status
                      properties:
                        id:
                          type: string
                        status:
                          type: integer
                        body: {}
                        location:
                          type: string
                  stopped:
                    type: boolean
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/fleet/commands:
    get:
      operationId: getFleetCommands
      tags:
      - Gateway
      summary: List fleet commands
      x-heart-level: module-fleet
      security:
      - oauth2:
        - heart.fleet
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
    post:
      operationId: postFleetCommands
      tags:
      - Gateway
      summary: Run one operation across selected systems, in stages
      description: 'Anything but a read waits for one person''s approval at the Gateway,
        with proof of presence over the fleet digest, which names every target. Each
        system then gets the operation with an approval the Gateway signs for that
        system alone (presence method fleet), and applies its own gate, guards and
        Stop (API Standard 13.3).'
      x-heart-level: module-fleet
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.fleet
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/fleet-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/fleet/commands/{id}:
    get:
      operationId: getFleetCommandsId
      tags:
      - Gateway
      summary: Progress per system
      x-heart-level: module-fleet
      security:
      - oauth2:
        - heart.fleet
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/id'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/fleet/commands/{id}/{control}:
    post:
      operationId: postFleetCommandsIdControl
      tags:
      - Gateway
      summary: Pause, resume or cancel a fleet command
      description: pause and cancel need no approval and stop further stages; systems
        already done stay done. resume needs a new human approval at the Gateway,
        with proof of presence, and is answered 202 with the Action (API Standard
        13.3, D30).
      x-heart-level: module-fleet
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.fleet
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/id'
      - name: control
        in: path
        required: true
        schema:
          enum:
          - pause
          - resume
          - cancel
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                reason:
                  type: string
                  maxLength: 500
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/systems/{ref}:
    delete:
      operationId: deleteSystemsRef
      tags:
      - Gateway
      summary: Remove a system from the Gateway
      x-heart-level: module-fleet
      x-heart-risk: write
      security:
      - oauth2:
        - heart.fleet
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: ref
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/custom:
    get:
      operationId: getCustom
      tags:
      - Custom
      summary: List custom definitions
      x-heart-level: module-custom
      parameters:
      - $ref: '#/components/parameters/cursor'
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Page'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
  /heart/v1/custom/{name}:
    get:
      operationId: getCustomName
      tags:
      - Custom
      summary: One definition
      x-heart-level: module-custom
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
    put:
      operationId: putCustomName
      tags:
      - Custom
      summary: Add or change a definition
      x-heart-level: module-custom
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/custom-definition.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
    delete:
      operationId: deleteCustomName
      tags:
      - Custom
      summary: Remove a definition
      x-heart-level: module-custom
      x-heart-risk: write
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/idempotencyKeyOptional'
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      responses:
        '204':
          description: Done.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/custom/{name}/preview:
    post:
      operationId: postCustomNamePreview
      tags:
      - Custom
      summary: Show the exact native request, without sending it
      x-heart-level: module-custom
      x-heart-risk: read
      security:
      - oauth2:
        - heart.configure
      - mtls: []
      parameters:
      - name: name
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/invoke-request.schema.json
      responses:
        '200':
          description: Result.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                type: object
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/native/{protocol}:
    post:
      operationId: postNativeProtocol
      tags:
      - Custom
      summary: Send one raw native request
      x-heart-level: module-native
      x-heart-risk: destructive
      security:
      - oauth2:
        - heart.native
      - mtls: []
      parameters:
      - name: protocol
        in: path
        required: true
        schema:
          type: string
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/native-request.schema.json
      responses:
        '200':
          $ref: '#/components/responses/Message'
        '202':
          description: Accepted. Poll Location or subscribe to heart.action.
          headers:
            Location:
              schema:
                type: string
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/cloudevents+json:
              schema:
                $ref: ../schemas/1.0/envelope.schema.json
        default:
          $ref: '#/components/responses/Problem'
  /heart/v1/serve:
    post:
      operationId: serve
      tags:
      - Core
      summary: Understand a plain request, check it and carry it out
      description: Defined in HEART-Core-Standard-1.0.md. The Core acts only through
        this same API, so every normal check applies.
      x-heart-level: module-core
      x-heart-risk: per-item
      security:
      - oauth2:
        - heart.ask
      - mtls: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: ../schemas/1.0/serve-request.schema.json
      responses:
        '200':
          description: Outcome.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/serve-response.schema.json
        '202':
          $ref: '#/components/responses/Accepted'
        default:
          $ref: '#/components/responses/Problem'
      parameters:
      - $ref: '#/components/parameters/idempotencyKey'
      - $ref: '#/components/parameters/dpop'
  /heart/v1/core:
    get:
      operationId: getCore
      tags:
      - Core
      summary: Core class, active tier and index version
      x-heart-level: module-core
      responses:
        '200':
          $ref: '#/components/responses/Message'
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
  /heart/v1/core/index:
    get:
      operationId: getCoreIndex
      tags:
      - Core
      summary: The API Index this Core understands
      x-heart-level: module-core
      responses:
        '200':
          description: API Index.
          headers:
            Heart-Version:
              $ref: '#/components/headers/HeartVersion'
          content:
            application/json:
              schema:
                $ref: ../schemas/1.0/api-index.schema.json
        default:
          $ref: '#/components/responses/Problem'
      security:
      - {}
      - oauth2:
        - heart.read
      - mtls: []
      parameters:
      - $ref: '#/components/parameters/dpop'
components:
  securitySchemes:
    oauth2:
      type: oauth2
      description: Access tokens are RFC 9068 JWTs carrying iss, aud (this system
        ID), exp (at most 15 minutes), sub, scope, heart_clearance, heart_caller,
        and cnf when bound. Over a network they MUST be sender-constrained with DPoP
        (RFC 9449, DPoP header) or mutual TLS (RFC 8705); see API Standard 8.2. Any
        view above public also needs heart.read.
      flows:
        clientCredentials:
          tokenUrl: https://issuer.example/token
          scopes:
            heart.read: Read messages at the granted clearance
            heart.ask: Ask questions
            heart.send: Post to the inbox
            heart.subscribe: Manage subscriptions
            heart.tend: Acknowledge alerts
            heart.propose: Deliver Proposals from a brain (Core Standard 7.3). Grants
              nothing else.
            heart.invoke: Invoke capabilities
            heart.approve: Approve or deny actions
            heart.reason: Call a Reasoning Gateway
            heart.configure: Change properties, settings, schedules and custom definitions
            heart.operate: Run diagnostics, lifecycle and software operations
            heart.admin: Change policies, autonomy, keys and peers
            heart.data: Manage consent and personal data
            heart.fleet: Run fleet commands and manage hosted systems
            heart.native: Send raw native requests
    mtls:
      type: mutualTLS
      description: Client certificate whose SAN URI names the principal. The owner
        keeps a table mapping it to clearance, scopes and caller kind; a certificate
        not in the table is a peer with clearance public and no scopes (API Standard
        8.2).
  headers:
    HeartVersion:
      description: Version of the standard the responder implements.
      schema:
        type: string
        examples:
        - '1.0'
    HeartCardSignature:
      description: Detached compact JWS (RFC 7515 Appendix F) over the exact response
        body, made with the identity key (API Standard 10.1). Required at Connected
        and above.
      schema:
        type: string
    HeartKeyRotation:
      description: 'For 7 days after a key rotation: the rotation statement, a compact
        JWS signed by the old key (API Standard 10.1, rule 7).'
      schema:
        type: string
    HeartReceiptSalt:
      description: base64url salt of the Valve receipt for this transfer, when it
        carries non-public data to a receipted recipient (API Standard 4.5).
      schema:
        type: string
        pattern: ^[A-Za-z0-9_-]{43,}$
  parameters:
    id:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    cursor:
      name: cursor
      in: query
      description: Opaque cursor from nextCursor.
      schema:
        type: string
    limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 500
        default: 100
    minSeverity:
      name: minSeverity
      in: query
      schema:
        type: string
        enum:
        - info
        - warning
        - error
        - critical
    idempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: 'Required on every POST that is not read, because a repeat would
        act twice. Scoped to (principal, operation), kept at least 24 hours. Missing:
        400 invalid-request. Same key, different body: 422 idempotency-conflict.'
      schema:
        type: string
        minLength: 8
        maxLength: 255
    idempotencyKeyOptional:
      name: Idempotency-Key
      in: header
      required: false
      description: 'Optional on PUT, PATCH and DELETE, and on acknowledge, resolve,
        silence and an Action decision: a repeat changes nothing more. One that waits
        for approval creates an Action; with a key, a retry returns that Action instead
        of creating another. Same rules as on POST.'
      schema:
        type: string
        minLength: 8
        maxLength: 255
    dpop:
      name: DPoP
      in: header
      required: false
      description: DPoP proof (RFC 9449). Required with a DPoP-bound token over a
        network.
      schema:
        type: string
  responses:
    Message:
      description: One HEART message.
      headers:
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
        Heart-Receipt-Salt:
          $ref: '#/components/headers/HeartReceiptSalt'
      content:
        application/cloudevents+json:
          schema:
            $ref: ../schemas/1.0/envelope.schema.json
    Page:
      description: A page of HEART messages.
      headers:
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
        Heart-Receipt-Salt:
          $ref: '#/components/headers/HeartReceiptSalt'
      content:
        application/json:
          schema:
            $ref: ../schemas/1.0/page.schema.json
    ReasonResult:
      description: Reasoning result.
      headers:
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
      content:
        application/json:
          schema:
            $ref: ../schemas/1.0/reason-response.schema.json
    Problem:
      description: RFC 9457 problem details with a HEART code.
      headers:
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
      content:
        application/problem+json:
          schema:
            $ref: ../schemas/1.0/problem.schema.json
    CardMessage:
      description: A HEART Card.
      headers:
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
        Heart-Card-Signature:
          $ref: '#/components/headers/HeartCardSignature'
        Heart-Key-Rotation:
          $ref: '#/components/headers/HeartKeyRotation'
        ETag:
          schema:
            type: string
        Cache-Control:
          schema:
            type: string
      content:
        application/cloudevents+json:
          schema:
            $ref: ../schemas/1.0/envelope.schema.json
    Accepted:
      description: 'Accepted: an Action was created that is running or awaiting approval
        (API Standard 6.3). Poll Location or subscribe to heart.action.'
      headers:
        Location:
          schema:
            type: string
        Heart-Version:
          $ref: '#/components/headers/HeartVersion'
      content:
        application/cloudevents+json:
          schema:
            $ref: ../schemas/1.0/envelope.schema.json
