openapi: "3.1.0"
info:
  title: Truecom Gateway API
  version: "1.0.0"
  description: AI agent payment infrastructure API

servers:
  - url: https://api.truecom.ai
    description: Production

security:
  - bearerAuth: []

paths:
  # ── Infrastructure ──────────────────────────────────────────────────────────
  /health:
    get:
      summary: Health check
      security: []
      tags: [Infrastructure]
      responses:
        "200":
          description: Service is healthy

  /healthz:
    get:
      summary: Liveness probe
      security: []
      tags: [Infrastructure]
      responses:
        "200":
          description: Service is live

  /readyz:
    get:
      summary: Readiness probe
      security: []
      tags: [Infrastructure]
      responses:
        "200":
          description: Service is ready

  /metrics:
    get:
      summary: Prometheus metrics
      security: []
      tags: [Infrastructure]
      responses:
        "200":
          description: Prometheus text format metrics

  /mcp:
    get:
      summary: Open a streamable HTTP MCP event stream
      security: []
      tags: [MCP]
      parameters:
        - name: mcp-protocol-version
          in: header
          required: false
          schema:
            type: string
            default: "2024-11-05"
      responses:
        "200":
          description: Server-sent event stream opened successfully
          content:
            text/event-stream:
              schema:
                type: string
        "400":
          $ref: "#/components/responses/BadRequest"
    post:
      summary: Invoke an MCP JSON-RPC request over streamable HTTP
      security: []
      tags: [MCP]
      parameters:
        - name: mcp-protocol-version
          in: header
          required: false
          schema:
            type: string
            default: "2024-11-05"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: JSON-RPC 2.0 request payload
      responses:
        "200":
          description: JSON-RPC response payload
          content:
            application/json:
              schema:
                type: object
        "429":
          description: Anonymous free tier exhausted
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      pay_at:
                        type: string
                        format: uri
        "400":
          $ref: "#/components/responses/BadRequest"
    delete:
      summary: Close a stateless MCP session handle
      security: []
      tags: [MCP]
      parameters:
        - name: mcp-protocol-version
          in: header
          required: false
          schema:
            type: string
            default: "2024-11-05"
      responses:
        "200":
          description: Session close acknowledged

  /mcp/healthz:
    get:
      summary: MCP transport liveness probe
      security: []
      tags: [MCP]
      responses:
        "200":
          description: MCP transport is live

  # ── Auth ────────────────────────────────────────────────────────────────────
  /v1/auth/apikey-exchange:
    post:
      summary: Exchange API key for access token
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                api_key:
                  type: string
      responses:
        "200":
          description: Access token issued
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/auth/signup:
    post:
      summary: Initiate signup
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
      responses:
        "200":
          description: Signup initiated; verification email sent
        "400":
          $ref: "#/components/responses/BadRequest"

  /v1/auth/signup/verify:
    post:
      summary: Verify signup OTP
      security: []
      tags: [Auth]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
      responses:
        "200":
          description: Account verified, access token issued
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TokenResponse"
        "400":
          $ref: "#/components/responses/BadRequest"

  /v1/auth/api-keys/rotate:
    post:
      summary: Rotate an API key
      tags: [Auth]
      responses:
        "200":
          description: New API key issued
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Credentials / DPoP ──────────────────────────────────────────────────────
  /v1/credentials/jwks:
    get:
      summary: Gateway JWKS endpoint
      security: []
      tags: [Credentials]
      responses:
        "200":
          description: JSON Web Key Set

  /v1/credentials/issue:
    post:
      summary: Issue a verifiable credential
      tags: [Credentials]
      responses:
        "200":
          description: Issued credential
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/credentials/verify:
    post:
      summary: Verify a verifiable credential
      tags: [Credentials]
      responses:
        "200":
          description: Verification result
        "400":
          $ref: "#/components/responses/BadRequest"

  # ── Registry ─────────────────────────────────────────────────────────────────
  /v1/registry/agents:
    post:
      summary: Register a new agent
      tags: [Registry]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AgentRegistrationRequest"
      responses:
        "201":
          description: Agent registered
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegistryEntry"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/registry/agents/{id}:
    get:
      summary: Get agent by internal ID
      tags: [Registry]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Registry entry
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegistryEntry"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      summary: Update agent registration
      tags: [Registry]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AgentRegistrationRequest"
      responses:
        "200":
          description: Updated registry entry
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegistryEntry"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      summary: Remove agent from registry
      tags: [Registry]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Agent removed
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/registry/did/{did}:
    get:
      summary: Look up agent by DID
      tags: [Registry]
      parameters:
        - name: did
          in: path
          required: true
          schema:
            type: string
          example: "did:web:agent.example.com"
      responses:
        "200":
          description: Registry entry
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RegistryEntry"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/registry/search:
    get:
      summary: Search registry by capability or metadata
      tags: [Registry]
      parameters:
        - name: q
          in: query
          schema:
            type: string
        - name: capability
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: "#/components/schemas/RegistryEntry"
                  total:
                    type: integer

  /v1/registry/discover:
    post:
      summary: Discover agents matching a task description
      tags: [Registry]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                task:
                  type: string
                constraints:
                  type: object
      responses:
        "200":
          description: Discovered agent candidates
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/RegistryEntry"

  /v1/registry/sync/relayone:
    post:
      summary: Sync registry from RelayOne
      tags: [Registry]
      responses:
        "200":
          description: Sync initiated
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Commerce ─────────────────────────────────────────────────────────────────
  /v1/wrap:
    post:
      summary: Wrap an outbound payment call
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WrapRequest"
      responses:
        "200":
          description: Wrap attestation recorded
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WrapResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/service/{slug}:
    get:
      summary: Load the public service card for a provider
      security: []
      tags: [Discovery]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
        - name: task
          in: query
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Service card with promoted gotchas and patterns
          content:
            application/json:
              schema:
                type: object
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/service/{slug}/report-outcome:
    post:
      summary: Submit a generalized outcome report for a provider
      tags: [Discovery]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                success:
                  type: boolean
                endpoint:
                  type: string
                latency_ms:
                  type: integer
                error_code:
                  type: string
                diagnosis:
                  type: string
                suggested_fix:
                  type: string
              required: [success]
      responses:
        "200":
          description: Report accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  report_id:
                    type: string
        "400":
          $ref: "#/components/responses/BadRequest"

  /v1/service/{slug}/report-pattern:
    post:
      summary: Submit a repeatable successful pattern for a provider
      tags: [Discovery]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                task:
                  type: string
                steps:
                  type: array
                  items:
                    type: object
                    properties:
                      step:
                        type: integer
                      endpoint:
                        type: string
                      note:
                        type: string
                    required: [step, endpoint]
                success:
                  type: boolean
                cost_usdc:
                  type: number
                latency_ms:
                  type: integer
              required: [task, steps, success]
      responses:
        "200":
          description: Pattern accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  report_id:
                    type: string
        "400":
          $ref: "#/components/responses/BadRequest"

  /v1/wrap/{wrap_id}/result:
    post:
      summary: Record wrap completion result
      tags: [Commerce]
      parameters:
        - name: wrap_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WrapResultRequest"
      responses:
        "200":
          description: Result recorded
        "400":
          $ref: "#/components/responses/BadRequest"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/intents:
    post:
      summary: Submit a payment intent (ingress)
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/IntentRequest"
      responses:
        "201":
          description: Intent created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntentResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/completions/{correlation_id}:
    post:
      summary: Record completion for an ingress intent
      tags: [Commerce]
      parameters:
        - name: correlation_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum: [success, failure]
                output_hash:
                  type: string
      responses:
        "200":
          description: Completion recorded
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/hire:
    post:
      summary: Hire an agent for a task
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/HireRequest"
      responses:
        "200":
          description: Agent hired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HireResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/settle:
    post:
      summary: Settle a completed engagement
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SettleRequest"
      responses:
        "200":
          description: Engagement settled
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/find:
    post:
      summary: Find agents capable of a task
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                task:
                  type: string
                budget_cents:
                  type: integer
                currency:
                  type: string
      responses:
        "200":
          description: Matching agents
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/RegistryEntry"

  /v1/verify-output:
    post:
      summary: Verify agent output against a task
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                task_id:
                  type: string
                  format: uuid
                output:
                  type: string
      responses:
        "200":
          description: Verification result
        "400":
          $ref: "#/components/responses/BadRequest"

  /v1/dispute:
    post:
      summary: Open a dispute on an engagement
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DisputeRequest"
      responses:
        "201":
          description: Dispute opened
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/disputes/{id}/resolve:
    post:
      summary: Resolve a dispute
      tags: [Commerce]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                resolution:
                  type: string
                note:
                  type: string
      responses:
        "200":
          description: Dispute resolved
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/fetch:
    post:
      summary: Fetch a URL with optional metered payment
      tags: [Commerce]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
                method:
                  type: string
                  default: GET
                max_payment_cents:
                  type: integer
      responses:
        "200":
          description: Fetch result
        "402":
          description: Payment required
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Payments ─────────────────────────────────────────────────────────────────
  /v1/payments/intents:
    post:
      summary: Create a Stripe payment intent
      tags: [Payments]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                currency:
                  type: string
      responses:
        "200":
          description: Payment intent created
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/webhooks/stripe:
    post:
      summary: Stripe webhook receiver
      security: []
      tags: [Payments]
      responses:
        "200":
          description: Event acknowledged

  # ── Balance ───────────────────────────────────────────────────────────────────
  /v1/balance/topup:
    post:
      summary: Add funds to agent balance
      tags: [Balance]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                currency:
                  type: string
      responses:
        "200":
          description: Balance updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BalanceResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/balance/withdraw:
    post:
      summary: Withdraw funds from agent balance
      tags: [Balance]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                currency:
                  type: string
      responses:
        "200":
          description: Withdrawal initiated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BalanceResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Audit ─────────────────────────────────────────────────────────────────────
  /v1/audit/query:
    get:
      summary: Query audit log
      tags: [Audit]
      parameters:
        - name: agent_id
          in: query
          schema:
            type: string
        - name: from
          in: query
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      responses:
        "200":
          description: Audit query result
          content:
            application/json:
              schema:
                type: object
                required: [records, total_count, chain_valid]
                properties:
                  records:
                    type: array
                    items:
                      $ref: "#/components/schemas/AuditEntry"
                  total_count:
                    type: integer
                    format: int64
                  chain_valid:
                    type: boolean
                    description: True only when chain integrity was verified for the queried scope; false when verification was not performed or failed.
                  merkle_proof:
                    type: object
                    nullable: true
                  verification_url:
                    type: string
                    nullable: true
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/audit/entry/{id}:
    get:
      summary: Get a single audit entry
      tags: [Audit]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Audit entry
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditEntry"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/audit/receipt/{receipt_id}:
    get:
      summary: Verify a payment receipt
      tags: [Audit]
      parameters:
        - name: receipt_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Receipt record
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/audit/proof/{id}:
    get:
      summary: Get Merkle proof for an audit entry
      tags: [Audit]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Merkle proof
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/audit/verify-chain:
    post:
      summary: Verify the audit chain integrity
      tags: [Audit]
      responses:
        "200":
          description: Chain verification result

  /v1/audit/export:
    post:
      summary: Export audit log
      tags: [Audit]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                from:
                  type: string
                  format: date-time
                to:
                  type: string
                  format: date-time
                format:
                  type: string
                  enum: [json, csv]
      responses:
        "200":
          description: Exported data
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/audit/compliance-report:
    get:
      summary: Generate compliance report
      tags: [Audit]
      responses:
        "200":
          description: Compliance report
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Settlement ────────────────────────────────────────────────────────────────
  /v1/settlement/batches:
    get:
      summary: List settlement batches
      tags: [Settlement]
      responses:
        "200":
          description: Settlement batches
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SettlementBatch"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/settlement/tickets/{id}:
    get:
      summary: Get settlement ticket by ID
      tags: [Settlement]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Settlement ticket
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SettlementTicket"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/settlement/swap-quote:
    get:
      summary: Get a swap quote for currency conversion
      tags: [Settlement]
      parameters:
        - name: from_currency
          in: query
          schema:
            type: string
        - name: to_currency
          in: query
          schema:
            type: string
        - name: amount_cents
          in: query
          schema:
            type: integer
      responses:
        "200":
          description: Swap quote

  # ── STC (Settlement Token Contract) ─────────────────────────────────────────
  /v1/authorize-settlement:
    post:
      summary: Authorize a settlement via STC
      tags: [STC]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                currency:
                  type: string
                recipient_did:
                  type: string
      responses:
        "200":
          description: Authorization token issued
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/verify-authorization/{token_id}:
    get:
      summary: Verify a settlement authorization token
      tags: [STC]
      parameters:
        - name: token_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Authorization details
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/settlement-callback:
    post:
      summary: Settlement callback from external rail
      security: []
      tags: [STC]
      responses:
        "200":
          description: Callback acknowledged

  /v1/approvals:
    get:
      summary: List pending approvals
      tags: [STC]
      responses:
        "200":
          description: Pending approvals
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/approvals/{approval_id}/status:
    get:
      summary: Get approval status
      tags: [STC]
      parameters:
        - name: approval_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Approval status
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/approvals/{approval_id}/decision:
    post:
      summary: Submit approval decision
      tags: [STC]
      parameters:
        - name: approval_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                decision:
                  type: string
                  enum: [approve, reject]
                reason:
                  type: string
      responses:
        "200":
          description: Decision recorded
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/stc/balance:
    get:
      summary: Get STC balance
      tags: [STC]
      responses:
        "200":
          description: STC balance
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/stc/payments:
    post:
      summary: Submit a payment via STC
      tags: [STC]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                recipient_did:
                  type: string
      responses:
        "200":
          description: Payment submitted
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/stc/rails/recommend:
    get:
      summary: Recommend settlement rail for a transaction
      tags: [STC]
      parameters:
        - name: amount_cents
          in: query
          schema:
            type: integer
        - name: currency
          in: query
          schema:
            type: string
      responses:
        "200":
          description: Recommended rail

  # ── Admin ────────────────────────────────────────────────────────────────────
  /v1/admin/api-keys:
    post:
      summary: Create an API key
      tags: [Admin]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type: string
                scopes:
                  type: array
                  items:
                    type: string
      responses:
        "201":
          description: API key created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    get:
      summary: List API keys
      tags: [Admin]
      responses:
        "200":
          description: API key list
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ApiKeyResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/admin/api-keys/{key_id}:
    delete:
      summary: Revoke an API key
      tags: [Admin]
      parameters:
        - name: key_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Key revoked
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/admin/ingress-keys:
    post:
      summary: Create an ingress key
      tags: [Admin]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                label:
                  type: string
      responses:
        "201":
          description: Ingress key created
        "401":
          $ref: "#/components/responses/Unauthorized"
    get:
      summary: List ingress keys
      tags: [Admin]
      responses:
        "200":
          description: Ingress key list
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/admin/ingress-keys/{id}:
    get:
      summary: Get ingress key by ID
      tags: [Admin]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Ingress key details
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      summary: Revoke an ingress key
      tags: [Admin]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Key revoked
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/admin/lp-balances:
    get:
      summary: Get liquidity pool balances
      tags: [Admin]
      responses:
        "200":
          description: LP balance list
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/admin/liquidity-pools:
    get:
      summary: List liquidity pools
      tags: [Admin]
      responses:
        "200":
          description: Liquidity pool list
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Agent / Identity ─────────────────────────────────────────────────────────
  /v1/agent/provision:
    post:
      summary: Provision a new agent
      tags: [Agents]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                did:
                  type: string
                metadata:
                  type: object
      responses:
        "201":
          description: Agent provisioned
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/agents/{did}/commerce/summary:
    get:
      summary: Get commerce summary for an agent
      tags: [Agents]
      parameters:
        - name: did
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Commerce summary
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/agents/{did}/commerce/history:
    get:
      summary: Get commerce history for an agent
      tags: [Agents]
      parameters:
        - name: did
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Commerce history entries

  /v1/agents/me/calibration:
    get:
      summary: Get calibration status for the calling agent
      tags: [Agents]
      responses:
        "200":
          description: Calibration state
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/agents/me/payout-config:
    get:
      summary: Get payout configuration
      tags: [Agents]
      responses:
        "200":
          description: Payout config
        "401":
          $ref: "#/components/responses/Unauthorized"
    put:
      summary: Set payout configuration
      tags: [Agents]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PayoutConfigRequest"
      responses:
        "200":
          description: Payout config updated
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/identity/{agent_id}:
    get:
      summary: Get identity record for an agent
      tags: [Identity]
      parameters:
        - name: agent_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Identity record
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/identity/{agent_id}/rotate:
    post:
      summary: Rotate keys for an agent identity
      tags: [Identity]
      parameters:
        - name: agent_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Keys rotated
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/identity/revoke:
    post:
      summary: Revoke identity by SPIFFE ID
      tags: [Identity]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                spiffe_id:
                  type: string
      responses:
        "200":
          description: Identity revoked
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/identity/reactivate:
    post:
      summary: Reactivate a revoked identity
      tags: [Identity]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                spiffe_id:
                  type: string
      responses:
        "200":
          description: Identity reactivated
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Delegation ────────────────────────────────────────────────────────────────
  /v1/delegation:
    post:
      summary: Create a delegation token
      tags: [Delegation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                delegate_did:
                  type: string
                scopes:
                  type: array
                  items:
                    type: string
                expires_at:
                  type: string
                  format: date-time
      responses:
        "201":
          description: Delegation token created
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/delegation/{token_id}/verify:
    get:
      summary: Verify a delegation token
      tags: [Delegation]
      parameters:
        - name: token_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Delegation details
        "404":
          $ref: "#/components/responses/NotFound"

  # ── Reputation ────────────────────────────────────────────────────────────────
  /v1/reputation/{agent_id}:
    get:
      summary: Get reputation for an agent
      tags: [Reputation]
      parameters:
        - name: agent_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Reputation record
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/reputation/{agent_id}/history:
    get:
      summary: Get reputation history for an agent
      tags: [Reputation]
      parameters:
        - name: agent_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Reputation history entries

  /v1/reputation/feedback:
    post:
      summary: Submit feedback on an agent
      tags: [Reputation]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                agent_id:
                  type: string
                rating:
                  type: number
                  minimum: 0
                  maximum: 5
                comment:
                  type: string
      responses:
        "201":
          description: Feedback recorded
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/reputation/feedback/{id}/dispute:
    post:
      summary: Dispute a feedback entry
      tags: [Reputation]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      responses:
        "200":
          description: Dispute submitted
        "404":
          $ref: "#/components/responses/NotFound"

  # ── Trust ────────────────────────────────────────────────────────────────────
  /v1/trust/scores:
    get:
      summary: List trust scores
      tags: [Trust]
      responses:
        "200":
          description: Trust score list
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/trust/scores/{entity_id}:
    get:
      summary: Get trust score for an entity
      tags: [Trust]
      parameters:
        - name: entity_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Trust score
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/trust/signals:
    post:
      summary: Submit a trust signal
      tags: [Trust]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                entity_id:
                  type: string
                signal_type:
                  type: string
                value:
                  type: number
      responses:
        "200":
          description: Signal recorded
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/trust/external/{endpoint}:
    get:
      summary: Get external trust data for an endpoint
      tags: [Trust]
      parameters:
        - name: endpoint
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: External trust data

  # ── TAP (Trust Attestation Protocol) ────────────────────────────────────────
  /v1/tap/sign:
    post:
      summary: Sign a TAP payload
      tags: [TAP]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                payload:
                  type: string
      responses:
        "200":
          description: Signed payload
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/tap/verify:
    post:
      summary: Verify a TAP signature
      tags: [TAP]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                signed_payload:
                  type: string
      responses:
        "200":
          description: Verification result

  # ── AP2 (Agent Payment Protocol v2) ─────────────────────────────────────────
  /v1/ap2/mandates:
    post:
      summary: Create an AP2 mandate
      tags: [AP2]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                recipient_did:
                  type: string
                amount_cents:
                  type: integer
                currency:
                  type: string
                recurring:
                  type: boolean
      responses:
        "201":
          description: Mandate created
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/ap2/mandates/{mandate_id}/verify:
    get:
      summary: Verify an AP2 mandate
      tags: [AP2]
      parameters:
        - name: mandate_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Mandate verification result
        "404":
          $ref: "#/components/responses/NotFound"

  # ── MPP (Multi-Party Payment) ─────────────────────────────────────────────────
  /v1/mpp/pay:
    post:
      summary: Execute a multi-party payment
      tags: [MPP]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                recipients:
                  type: array
                  items:
                    type: object
                    properties:
                      did:
                        type: string
                      share_bps:
                        type: integer
      responses:
        "200":
          description: Payment distributed
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/mpp/sessions:
    post:
      summary: Open an MPP session
      tags: [MPP]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                participants:
                  type: array
                  items:
                    type: string
      responses:
        "201":
          description: Session opened
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/mpp/sessions/{session_id}:
    delete:
      summary: Close an MPP session
      tags: [MPP]
      parameters:
        - name: session_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Session closed
        "404":
          $ref: "#/components/responses/NotFound"

  # ── ACP (Agent Checkout Protocol) ─────────────────────────────────────────────
  /v1/acp/checkout:
    post:
      summary: Create an ACP checkout session
      tags: [ACP]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                amount_cents:
                  type: integer
                currency:
                  type: string
                description:
                  type: string
      responses:
        "201":
          description: Checkout session created
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/acp/checkout/{session_id}/complete:
    post:
      summary: Complete an ACP checkout session
      tags: [ACP]
      parameters:
        - name: session_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Checkout completed
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/acp/checkout/{session_id}:
    delete:
      summary: Cancel an ACP checkout session
      tags: [ACP]
      parameters:
        - name: session_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: Session cancelled
        "404":
          $ref: "#/components/responses/NotFound"

  # ── Inference Wrap ─────────────────────────────────────────────────────────────
  /v1/inference/wrap:
    post:
      summary: Wrap an inference call with metered billing
      tags: [Inference]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                model:
                  type: string
                prompt:
                  type: string
                max_tokens:
                  type: integer
      responses:
        "200":
          description: Inference result with billing receipt
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/inference/wrap/{correlation_id}/result:
    post:
      summary: Record inference wrap completion
      tags: [Inference]
      parameters:
        - name: correlation_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tokens_used:
                  type: integer
                cost_cents:
                  type: integer
      responses:
        "200":
          description: Result recorded
        "404":
          $ref: "#/components/responses/NotFound"

  # ── Policies ──────────────────────────────────────────────────────────────────
  /v1/policies/evaluate:
    post:
      summary: Evaluate a Cedar policy
      tags: [Policies]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                policy:
                  type: string
                principal:
                  type: string
                action:
                  type: string
                resource:
                  type: string
      responses:
        "200":
          description: Policy evaluation result
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/policies/rules:
    get:
      summary: List active policy rules
      tags: [Policies]
      responses:
        "200":
          description: Policy rules list
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Contexts ──────────────────────────────────────────────────────────────────
  /v1/contexts/{context_id}:
    get:
      summary: Get a shared context
      tags: [Contexts]
      parameters:
        - name: context_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Context record
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/contexts/{context_id}/contribute:
    post:
      summary: Contribute to a shared context
      tags: [Contexts]
      parameters:
        - name: context_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: object
      responses:
        "200":
          description: Contribution recorded
        "401":
          $ref: "#/components/responses/Unauthorized"

  # ── Verification ──────────────────────────────────────────────────────────────
  /v1/verification/runs/{id}:
    get:
      summary: Get verification run by ID
      tags: [Verification]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Verification run record
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/verifiers/{did}/calibration/challenge:
    post:
      summary: Issue a calibration challenge to a verifier
      tags: [Verification]
      parameters:
        - name: did
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                test_case_id:
                  type: string
                  format: uuid
                content:
                  type: string
                expected_result:
                  type: string
                difficulty:
                  type: string
      responses:
        "200":
          description: Challenge issued
        "401":
          $ref: "#/components/responses/Unauthorized"

  /v1/verifiers/{did}/calibration/response:
    post:
      summary: Submit calibration challenge response
      tags: [Verification]
      parameters:
        - name: did
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                challenge_id:
                  type: string
                  format: uuid
                result:
                  type: string
                confidence:
                  type: number
                  minimum: 0
                  maximum: 1
      responses:
        "200":
          description: Response recorded
        "401":
          $ref: "#/components/responses/Unauthorized"

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        Bearer token obtained via /v1/auth/apikey-exchange or /v1/auth/signup/verify.
        DPoP-bound tokens are also supported; include a `DPoP` header with the proof JWT.

  responses:
    BadRequest:
      description: Bad request — invalid or missing parameters
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Unauthorized:
      description: Authentication required or token invalid
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

  schemas:
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: string
          description: Human-readable error message

    TokenResponse:
      type: object
      required: [access_token, token_type]
      properties:
        access_token:
          type: string
        token_type:
          type: string
          example: Bearer
        expires_in:
          type: integer
          description: Seconds until expiry

    RegistryEntry:
      type: object
      required: [did, registry_tier]
      properties:
        did:
          type: string
        registry_tier:
          type: string
          enum: [listed, unlisted, blocked]
        trust_score:
          type: number
          nullable: true
        capabilities:
          type: array
          items:
            type: string
        pricing_model:
          type: string
          nullable: true
        sovereignty:
          type: object
          properties:
            regions:
              type: array
              items:
                type: string
            frameworks:
              type: array
              items:
                type: string
            verified:
              type: boolean
        calibration_catch_rate:
          type: number
          nullable: true
        uptime_30d:
          type: number
          nullable: true
        promoted:
          type: boolean
        source:
          type: string
        registered_at:
          type: string
          format: date-time
          nullable: true
        last_active_at:
          type: string
          format: date-time
          nullable: true

    AgentRegistrationRequest:
      type: object
      required: [did]
      properties:
        did:
          type: string
        capabilities:
          type: array
          items:
            type: string
        pricing_model:
          type: string
        metadata:
          type: object

    WrapRequest:
      type: object
      required: [rail, endpoint, amount_cents, currency]
      properties:
        rail:
          type: string
          description: Payment rail identifier
        endpoint:
          type: string
          format: uri
          description: Target endpoint URL
        amount_cents:
          type: integer
          minimum: 1
        currency:
          type: string
          example: USD
        body:
          type: object
          nullable: true
          description: Request body to forward
        headers:
          type: object
          additionalProperties:
            type: string
          description: Additional headers to include
        method:
          type: string
          default: POST
          enum: [GET, POST, PUT, PATCH, DELETE]

    WrapResponse:
      type: object
      required: [wrap_id, correlation_id, status, rail, endpoint, reputation_recorded, event_published]
      properties:
        wrap_id:
          type: string
          format: uuid
          description: Unique ID for this wrap operation
        correlation_id:
          type: string
          format: uuid
          description: >
            Alias for wrap_id. Router-Core uses this field to correlate
            completion events posted to /v1/wrap/:wrap_id/result.
        status:
          type: string
          example: attestation_recorded
        rail:
          type: string
        endpoint:
          type: string
          format: uri
        reputation_recorded:
          type: boolean
        event_published:
          type: boolean

    WrapResultRequest:
      type: object
      required: [status_code]
      properties:
        status_code:
          type: integer
        response_hash:
          type: string
          nullable: true

    IntentRequest:
      type: object
      required: [amount_cents, currency]
      properties:
        amount_cents:
          type: integer
          minimum: 1
        currency:
          type: string
        description:
          type: string
        metadata:
          type: object

    IntentResponse:
      type: object
      required: [intent_id, status]
      properties:
        intent_id:
          type: string
          format: uuid
        status:
          type: string
        correlation_id:
          type: string
          format: uuid

    HireRequest:
      type: object
      required: [agent_did, task]
      properties:
        agent_did:
          type: string
        task:
          type: string
        budget_cents:
          type: integer
        currency:
          type: string
        deadline:
          type: string
          format: date-time

    HireResponse:
      type: object
      required: [engagement_id, status]
      properties:
        engagement_id:
          type: string
          format: uuid
        status:
          type: string
        agent_did:
          type: string

    SettleRequest:
      type: object
      required: [engagement_id]
      properties:
        engagement_id:
          type: string
          format: uuid
        outcome:
          type: string
          enum: [success, partial, failure]
        output_hash:
          type: string

    DisputeRequest:
      type: object
      required: [engagement_id, reason]
      properties:
        engagement_id:
          type: string
          format: uuid
        reason:
          type: string
        evidence:
          type: string

    BalanceResponse:
      type: object
      required: [agent_id, balance_cents, currency]
      properties:
        agent_id:
          type: string
        balance_cents:
          type: integer
        currency:
          type: string

    AuditEntry:
      type: object
      required: [id, event_type, agent_id, timestamp]
      properties:
        id:
          type: string
          format: uuid
        event_type:
          type: string
        agent_id:
          type: string
        amount_cents:
          type: integer
          nullable: true
        currency:
          type: string
          nullable: true
        timestamp:
          type: string
          format: date-time
        merkle_hash:
          type: string
          nullable: true
        metadata:
          type: object
          nullable: true

    SettlementBatch:
      type: object
      required: [batch_id, status, created_at]
      properties:
        batch_id:
          type: string
          format: uuid
        status:
          type: string
          enum: [pending, processing, settled, failed]
        total_cents:
          type: integer
        currency:
          type: string
        ticket_count:
          type: integer
        created_at:
          type: string
          format: date-time
        settled_at:
          type: string
          format: date-time
          nullable: true

    SettlementTicket:
      type: object
      required: [ticket_id, batch_id, status]
      properties:
        ticket_id:
          type: string
          format: uuid
        batch_id:
          type: string
          format: uuid
        status:
          type: string
        amount_cents:
          type: integer
        currency:
          type: string

    ApiKeyResponse:
      type: object
      required: [key_id, created_at]
      properties:
        key_id:
          type: string
          format: uuid
        label:
          type: string
          nullable: true
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        key:
          type: string
          description: >
            Raw key value — only present on creation, never returned again.
          nullable: true

    PayoutConfigRequest:
      type: object
      required: [method]
      properties:
        method:
          type: string
          enum: [stripe_connect, usdc, ach]
        stripe_connect_account_id:
          type: string
          nullable: true
        usdc_address:
          type: string
          nullable: true
        ach_routing:
          type: string
          nullable: true
        ach_account:
          type: string
          nullable: true
