openapi: 3.1.0
info:
  title: ItPay V3 API
  version: 0.1.0
  description: >
    Draft contract for the V3 rewrite. The UX stays the same: CLI creates a
    checkout QR, frontend owns the human flow, backend owns canonical state.
servers:
  - url: https://sandbox.itpay.ai
    description: Sandbox
tags:
  - name: protocol
  - name: catalog
  - name: checkout
  - name: dashboard
  - name: identity
  - name: order
  - name: refund
  - name: vault
  - name: service-execution
  - name: merchant
  - name: admin
  - name: provider
  - name: local-dev
paths:
  /.well-known/ucp:
    get:
      tags: [protocol]
      operationId: getUCPWellKnownProfile
      summary: Compatibility discovery for UCP clients.
      responses:
        "200":
          description: Active UCP protocol profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProtocolProfile"

  /api/ucp/profile:
    get:
      tags: [protocol]
      operationId: getLegacyUCPProfile
      summary: Legacy UCP facade backed by the active V3 protocol profile.
      responses:
        "200":
          description: Active UCP protocol profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProtocolProfile"

  /v1/readyz:
    get:
      tags: [checkout]
      operationId: getReady
      responses:
        "200":
          description: Service is ready.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReadyResponse"

  /v1/platform/compatibility:
    get:
      tags: [protocol]
      operationId: getPlatformCompatibility
      summary: Active platform, schema, bootstrap, API contract, and CLI compatibility revisions.
      responses:
        "200":
          description: Active platform compatibility contract.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlatformCompatibility"

  /v1/catalog/manifest:
    get:
      tags: [catalog]
      operationId: getCatalogManifest
      summary: Public catalog manifest used by CLI discovery and shelf views.
      responses:
        "200":
          description: Published catalog manifest.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogManifest"

  /v1/catalog/snapshots/{catalog_snapshot_id}:
    get:
      tags: [catalog]
      operationId: getCatalogSnapshot
      parameters:
        - $ref: "#/components/parameters/CatalogSnapshotID"
      responses:
        "200":
          description: Catalog snapshot content.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogSnapshot"

  /v1/catalog/deltas:
    get:
      tags: [catalog]
      operationId: getCatalogDelta
      summary: Public catalog delta between two snapshot versions.
      parameters:
        - name: from_snapshot_version
          in: query
          required: true
          schema:
            type: string
        - name: to_snapshot_version
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Catalog delta content.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CatalogDelta"

  /v1/carts:
    post:
      tags: [checkout]
      operationId: createCart
      summary: Create a canonical server cart from selected offer lines.
      security:
        - AgentDeviceSession: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateCartRequest"
      responses:
        "201":
          description: Cart created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cart"

  /v1/carts/{cart_id}:
    get:
      tags: [checkout]
      operationId: getCart
      summary: Read a canonical server cart.
      security:
        - AgentDeviceSession: []
      parameters:
        - name: cart_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cart read.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cart"
    delete:
      tags: [checkout]
      operationId: abandonCart
      summary: Abandon a canonical server cart and soft-remove active lines.
      security:
        - AgentDeviceSession: []
      parameters:
        - name: cart_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cart abandoned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cart"
        "409":
          description: Cart contains checkout-bound or quote-locked lines.

  /v1/carts/{cart_id}/items:
    post:
      tags: [checkout]
      operationId: addCartItem
      summary: Add one line to a canonical server cart.
      security:
        - AgentDeviceSession: []
      parameters:
        - name: cart_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddCartItemRequest"
      responses:
        "201":
          description: Cart item added.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cart"

  /v1/carts/{cart_id}/items/{cart_item_id}:
    delete:
      tags: [checkout]
      operationId: removeCartItem
      summary: Soft-remove one active line from a canonical server cart.
      security:
        - AgentDeviceSession: []
      parameters:
        - name: cart_id
          in: path
          required: true
          schema:
            type: string
        - name: cart_item_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Cart item removed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cart"
        "409":
          description: Cart item is checkout-bound or quote-locked.

  /v1/checkouts:
    post:
      tags: [checkout]
      operationId: createCheckout
      summary: Create a checkout and checkout QR payload for CLI rendering.
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: Replay the same pending Checkout with a rotated short-lived handoff instead of creating a duplicate.
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateCheckoutRequest"
      responses:
        "201":
          description: Checkout created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutCreated"

  /v1/checkouts/{checkout_id}/presentation:
    get:
      tags: [checkout]
      operationId: getCheckoutPresentation
      summary: Load the human checkout page after scanning the checkout QR.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
        - name: display_token
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Checkout presentation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutPresentation"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/checkouts/{checkout_id}/events:
    get:
      tags: [checkout]
      operationId: streamCheckoutEvents
      summary: SSE stream scoped by checkout display token.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
        - name: display_token
          in: query
          required: true
          schema:
            type: string
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: string
        - name: replay
          in: query
          required: false
          schema:
            type: string
            enum: [once]
      responses:
        "200":
          description: Server-sent domain events.
          content:
            text/event-stream:
              schema:
                type: string

  /v1/checkouts/{checkout_id}/auth-sessions:
    post:
      tags: [checkout]
      operationId: createBuyerAuthSession
      summary: Start checkout-bound buyer auth.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateBuyerAuthSessionRequest"
      responses:
        "202":
          description: Auth session accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuyerAuthSession"

  /v1/checkouts/{checkout_id}/auth/alipay-code:
    post:
      tags: [checkout]
      operationId: completeBuyerAuthWithAlipayCode
      summary: Complete checkout-bound Alipay auth from frontend JS bridge auth_code.
      description: |
        Used inside the Alipay client to avoid a full-page OAuth redirect during
        checkout load. The frontend obtains `auth_code` asynchronously through
        the Alipay JS bridge, then exchanges it here with the checkout display
        token. The response is the refreshed checkout presentation.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompleteBuyerAuthWithAlipayCodeRequest"
      responses:
        "200":
          description: Alipay authorization completed and checkout presentation refreshed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutPresentation"

  /v1/checkouts/{checkout_id}/auth/wechat-code:
    post:
      tags: [checkout]
      operationId: completeBuyerAuthWithWechatCode
      summary: Complete checkout-bound WeChat OAuth code exchange.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompleteBuyerAuthWithAlipayCodeRequest"
      responses:
        "200":
          description: WeChat authorization completed and checkout presentation refreshed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutPresentation"

  /v1/checkouts/{checkout_id}/payment-intents:
    post:
      tags: [checkout]
      operationId: createPaymentIntent
      summary: Human-initiated payment command from the frontend checkout page.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePaymentIntentRequest"
      responses:
        "202":
          description: Payment intent accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentIntent"
        "400":
          description: Payment method or display token is missing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Checkout and display token do not identify an active checkout entry.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/checkouts/{checkout_id}/complete-exchange:
    post:
      tags: [checkout]
      operationId: completeCheckoutExchange
      summary: Complete paid checkout handoff and return exactly one frontend session.
      description: |
        Consumes the one-time `display_token` whose purpose is `complete_exchange`,
        verifies that a payment proof exists for this checkout, and returns the
        resolved order id plus a frontend session DTO.

        The returned session has `scope=account` so that the frontend dashboard
        and orders pages can render canonical backend state without re-login.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompleteCheckoutExchangeRequest"
      responses:
        "200":
          description: Exchange completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompleteCheckoutExchangeResponse"
        "404":
          description: Checkout or display token not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Payment proof missing or checkout/order buyer binding is incomplete.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/checkouts/{checkout_id}/receipt-exchange:
    post:
      tags: [checkout]
      operationId: exchangePaymentReceipt
      summary: Exchange a one-time receipt link for an order-scoped session.
      description: |
        Verifies an accepted payment proof and a browser-bound receipt token.
        The returned session can read only the order created by this checkout;
        it does not grant account Dashboard or other-order access.
      parameters:
        - $ref: "#/components/parameters/CheckoutID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReceiptExchangeRequest"
      responses:
        "200":
          description: Order-scoped session created or idempotently recovered for the same browser binding.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReceiptExchangeResponse"
        "404":
          description: Receipt token is invalid, expired, or bound to another browser.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: Payment proof or buyer binding is missing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/dashboard/auth-sessions:
    post:
      tags: [dashboard]
      operationId: createDashboardAuthSession
      summary: Start dashboard scan-login.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                provider:
                  type: string
                  enum: [alipay, wechat]
                  default: alipay
      responses:
        "201":
          description: Dashboard auth session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardAuthSession"

  /v1/dashboard/auth-sessions/{dashboard_auth_session_id}:
    get:
      tags: [dashboard]
      operationId: getDashboardAuthSession
      parameters:
        - $ref: "#/components/parameters/DashboardAuthSessionID"
        - name: poll_token
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Dashboard auth session status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardAuthSession"

  /v1/dashboard/auth-sessions/{dashboard_auth_session_id}/events:
    get:
      tags: [dashboard]
      operationId: streamDashboardAuthSessionEvents
      summary: SSE stream for dashboard scan-login status.
      parameters:
        - $ref: "#/components/parameters/DashboardAuthSessionID"
        - name: poll_token
          in: query
          required: true
          schema:
            type: string
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: string
        - name: replay
          in: query
          required: false
          schema:
            type: string
            enum: [once]
      responses:
        "200":
          description: Server-sent domain events.
          content:
            text/event-stream:
              schema:
                type: string

  /v1/dashboard/auth-sessions/{dashboard_auth_session_id}/claim:
    post:
      tags: [dashboard]
      operationId: claimDashboardAuthSession
      parameters:
        - $ref: "#/components/parameters/DashboardAuthSessionID"
        - name: start_token
          in: query
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Account session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuyerSession"

  /v1/me/profile:
    get:
      tags: [identity]
      operationId: getBuyerProfile
      summary: Account profile for dashboard and delivery contact defaults.
      responses:
        "200":
          description: Buyer profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuyerProfile"
    patch:
      tags: [identity]
      operationId: updateBuyerProfile
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateBuyerProfileRequest"
      responses:
        "200":
          description: Updated buyer profile.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BuyerProfile"

  /v1/me/events:
    get:
      tags: [dashboard]
      operationId: streamAccountEvents
      summary: SSE stream for dashboard account updates.
      parameters:
        - name: session_token
          in: query
          required: false
          schema:
            type: string
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: string
        - name: replay
          in: query
          required: false
          schema:
            type: string
            enum: [once]
      responses:
        "200":
          description: Server-sent domain events.
          content:
            text/event-stream:
              schema:
                type: string

  /v1/me/orders:
    get:
      tags: [dashboard, order]
      operationId: listAccountOrders
      summary: List account orders for dashboard.
      parameters:
        - name: status
          in: query
          required: false
          schema:
            type: string
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum: [created_at_desc, created_at_asc]
            default: created_at_desc
        - name: cursor
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Account orders.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListOrdersResponse"
        "403":
          description: Session is not account-scoped.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/orders/{order_id}:
    get:
      tags: [order]
      operationId: getOrder
      parameters:
        - $ref: "#/components/parameters/OrderID"
      responses:
        "200":
          description: Canonical order status and delivery view.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Order"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/orders/{order_id}/delivery-access:
    get:
      tags: [order, vault]
      operationId: getOrderDeliveryAccess
      parameters:
        - $ref: "#/components/parameters/OrderID"
      responses:
        "200":
          description: Owner-safe delivery metadata. Email claim credentials are never returned here.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrderDeliveryAccess"
        "403":
          description: Session is not allowed to access this order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/orders/{order_id}/delivery-redemptions:
    post:
      tags: [order, vault]
      operationId: redeemOwnerDelivery
      summary: Redeem a delivery as the authenticated account-scoped order owner.
      parameters:
        - $ref: "#/components/parameters/OrderID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [vault_artifact_id]
              properties:
                vault_artifact_id:
                  type: string
      responses:
        "201":
          description: Idempotent order-scoped delivery session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OwnerDeliveryRedemption"
        "403":
          description: Account session does not own the order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/orders/{order_id}/events:
    get:
      tags: [order]
      operationId: streamOrderEvents
      parameters:
        - $ref: "#/components/parameters/OrderID"
        - name: session_token
          in: query
          required: false
          schema:
            type: string
        - name: Last-Event-ID
          in: header
          required: false
          schema:
            type: string
        - name: replay
          in: query
          required: false
          schema:
            type: string
            enum: [once]
      responses:
        "200":
          description: Server-sent domain events.
          content:
            text/event-stream:
              schema:
                type: string

  /v1/orders/{order_id}/refunds:
    get:
      tags: [refund]
      operationId: listOrderRefunds
      parameters:
        - $ref: "#/components/parameters/OrderID"
      responses:
        "200":
          description: Refund requests for an order.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListRefundsResponse"
    post:
      tags: [refund]
      operationId: createRefund
      parameters:
        - $ref: "#/components/parameters/OrderID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRefundRequest"
      responses:
        "202":
          description: Refund request accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RefundRequest"

  /v1/refunds/{refund_request_id}:
    get:
      tags: [refund]
      operationId: getRefund
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      responses:
        "200":
          description: Refund status.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RefundRequest"

  /v1/refunds/{refund_request_id}/cancel:
    post:
      tags: [refund]
      operationId: cancelRefund
      summary: Cancel a refund before provider submission.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateRefundRequest"
      responses:
        "200":
          description: Refund cancelled and delivery access restored.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RefundRequest"
        "409":
          description: Provider submission has started and cancellation is no longer safe.

  /v1/orders/{order_id}/feedback:
    get:
      tags: [feedback]
      operationId: listOrderServiceFeedback
      parameters:
        - $ref: "#/components/parameters/OrderID"
      responses:
        "200":
          description: Feedback submitted against this order (buyer and/or agent).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListServiceFeedbackResponse"
    post:
      tags: [feedback]
      operationId: submitServiceFeedback
      summary: Submit (or replace) feedback for a service order item.
      description: |
        Buyer identity comes from an account/order-scoped session. Agent identity comes
        from a signed Agent Device session and must match the order item's Service Execution.
        A unique (order_item_id, submitter_kind) record is upserted.
      parameters:
        - $ref: "#/components/parameters/OrderID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubmitServiceFeedbackRequest"
      responses:
        "201":
          description: Feedback accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubmitServiceFeedbackResponse"

  /v1/admin/feedback:
    get:
      tags: [admin, feedback]
      operationId: listAdminServiceFeedback
      parameters:
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [new, acknowledged, resolved, dismissed]
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
      responses:
        "200":
          description: Admin feedback queue.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListAdminServiceFeedbackResponse"

  /v1/admin/feedback/{feedback_id}:
    get:
      tags: [admin, feedback]
      operationId: getAdminServiceFeedback
      parameters:
        - $ref: "#/components/parameters/FeedbackID"
      responses:
        "200":
          description: Single feedback.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GetAdminServiceFeedbackResponse"
    patch:
      tags: [admin, feedback]
      operationId: adminUpdateServiceFeedback
      parameters:
        - $ref: "#/components/parameters/FeedbackID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminUpdateServiceFeedbackRequest"
      responses:
        "200":
          description: Updated feedback.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminUpdateServiceFeedbackResponse"

  /v1/vault/artifacts/{vault_artifact_id}:
    get:
      tags: [vault]
      operationId: getVaultArtifact
      parameters:
        - $ref: "#/components/parameters/VaultArtifactID"
      responses:
        "200":
          description: Redacted or revealable vault artifact.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VaultArtifact"

  /v1/delivery-claims/{claim_link_id}/exchange:
    post:
      tags: [vault]
      operationId: exchangeDeliveryClaim
      parameters:
        - name: claim_link_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ClaimDeliveryExchangeRequest"
      responses:
        "200":
          description: Claim exchanged for an order-scoped buyer session.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClaimDeliveryExchangeResponse"
        "409":
          description: A valid claim was bound to another browser and requires order-owner reauthentication.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "410":
          description: Claim expired or was revoked.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/vault/artifacts/{vault_artifact_id}/agent-read-grants/session-consent:
    post:
      tags: [vault]
      operationId: createAgentReadGrantBySessionConsent
      summary: Create a temporary agent read grant after human page consent.
      parameters:
        - $ref: "#/components/parameters/VaultArtifactID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateAgentReadGrantRequest"
      responses:
        "201":
          description: Agent read grant created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentReadGrant"

  /v1/merchant/statements:
    get:
      tags: [merchant]
      operationId: listMerchantStatements
      parameters:
        - name: merchant_id
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Merchant statements.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListMerchantStatementsResponse"

  /v1/merchant/statements/{merchant_statement_id}:
    get:
      tags: [merchant]
      operationId: getMerchantStatement
      parameters:
        - $ref: "#/components/parameters/MerchantStatementID"
      responses:
        "200":
          description: Merchant statement with lines.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MerchantStatement"

  /v1/merchant/statements/{merchant_statement_id}/exports:
    get:
      tags: [merchant]
      operationId: listMerchantStatementExports
      parameters:
        - $ref: "#/components/parameters/MerchantStatementID"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Merchant statement export metadata.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListMerchantStatementExportsResponse"
    post:
      tags: [merchant]
      operationId: createMerchantStatementExport
      parameters:
        - $ref: "#/components/parameters/MerchantStatementID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateMerchantStatementExportRequest"
      responses:
        "201":
          description: Merchant statement export metadata created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MerchantStatementExport"

  /v1/admin/ledger-entries:
    get:
      tags: [admin]
      operationId: listAdminLedgerEntries
      parameters:
        - name: merchant_id
          in: query
          required: false
          schema:
            type: string
        - name: order_id
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 200
      responses:
        "200":
          description: Ledger entries for admin finance views.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListLedgerEntriesResponse"

  /v1/admin/provider-statement-imports:
    get:
      tags: [admin]
      operationId: listProviderStatementImports
      responses:
        "200":
          description: Provider statement imports.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListProviderStatementImportsResponse"
    post:
      tags: [admin]
      operationId: createProviderStatementImport
      summary: Register provider statement import metadata for reconciliation.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateProviderStatementImportRequest"
      responses:
        "201":
          description: Provider statement import registered.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProviderStatementImport"

  /v1/admin/provider-statement-imports/{provider_statement_import_id}/lines:
    get:
      tags: [admin]
      operationId: listProviderStatementLines
      summary: List parsed provider statement lines for an import.
      parameters:
        - name: provider_statement_import_id
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 500
      responses:
        "200":
          description: Provider statement lines.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListProviderStatementLinesResponse"
    post:
      tags: [admin]
      operationId: importProviderStatementLines
      summary: Import parsed provider statement lines.
      parameters:
        - name: provider_statement_import_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ImportProviderStatementLinesRequest"
      responses:
        "201":
          description: Imported provider statement lines.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListProviderStatementLinesResponse"

  /v1/admin/merchant-kyb-cases:
    get:
      tags: [admin]
      operationId: listMerchantKYBCases
      summary: List merchant KYB cases.
      parameters:
        - name: merchant_id
          in: query
          required: false
          schema:
            type: string
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [draft, submitted, approved, rejected, expired]
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Merchant KYB cases.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListMerchantKYBCasesResponse"
    post:
      tags: [admin]
      operationId: createMerchantKYBCase
      summary: Create a draft merchant KYB case.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateMerchantKYBCaseRequest"
      responses:
        "201":
          description: Merchant KYB case created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MerchantKYBCase"

  /v1/admin/merchant-kyb-cases/{kyb_case_id}:
    patch:
      tags: [admin]
      operationId: updateMerchantKYBCase
      summary: Submit or decide a merchant KYB case.
      parameters:
        - name: kyb_case_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateMerchantKYBCaseRequest"
      responses:
        "200":
          description: Merchant KYB case updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UpdateMerchantKYBCaseResponse"

  /v1/admin/policy-decisions:
    get:
      tags: [admin]
      operationId: listPolicyDecisions
      summary: List policy decisions for audit views.
      parameters:
        - name: subject_type
          in: query
          required: false
          schema:
            type: string
        - name: subject_id
          in: query
          required: false
          schema:
            type: string
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Policy decisions.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListPolicyDecisionsResponse"

  /v1/admin/reconciliation-runs:
    get:
      tags: [admin]
      operationId: listAdminReconciliationRuns
      responses:
        "200":
          description: Reconciliation runs.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListReconciliationRunsResponse"
    post:
      tags: [admin]
      operationId: createReconciliationRun
      summary: Admin-only command to request reconciliation execution.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateReconciliationRunRequest"
      responses:
        "202":
          description: Reconciliation execution requested.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExecutionRequest"

  /v1/admin/reconciliation-runs/{reconciliation_run_id}/mismatches:
    get:
      tags: [admin]
      operationId: listAdminReconciliationMismatches
      parameters:
        - $ref: "#/components/parameters/ReconciliationRunID"
      responses:
        "200":
          description: Reconciliation mismatches.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListReconciliationMismatchesResponse"

  /v1/admin/reconciliation-runs/{reconciliation_run_id}/result:
    post:
      tags: [admin]
      operationId: projectReconciliationResult
      summary: Project execution-computed reconciliation matches and mismatches.
      parameters:
        - $ref: "#/components/parameters/ReconciliationRunID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectReconciliationResultRequest"
      responses:
        "200":
          description: Reconciliation result projected.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReconciliationProjectionResult"

  /v1/admin/reconciliation-mismatches/{reconciliation_mismatch_id}:
    patch:
      tags: [admin]
      operationId: updateReconciliationMismatch
      summary: Resolve or ignore an admin reconciliation mismatch.
      parameters:
        - $ref: "#/components/parameters/ReconciliationMismatchID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateReconciliationMismatchRequest"
      responses:
        "200":
          description: Updated reconciliation mismatch.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReconciliationMismatch"

  /v1/admin/settlement-batches:
    get:
      tags: [admin]
      operationId: listAdminSettlementBatches
      responses:
        "200":
          description: Settlement batches.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListSettlementBatchesResponse"

  /v1/admin/settlement-batches/{settlement_batch_id}/finalize:
    post:
      tags: [admin]
      operationId: finalizeSettlementBatch
      summary: Finalize a settlement batch read model.
      parameters:
        - $ref: "#/components/parameters/SettlementBatchID"
      responses:
        "200":
          description: Finalized settlement batch.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SettlementBatch"

  /v1/admin/settlement-batches/{settlement_batch_id}/mark-paid:
    post:
      tags: [admin]
      operationId: markSettlementBatchPaid
      summary: Mark a finalized settlement batch as paid.
      parameters:
        - $ref: "#/components/parameters/SettlementBatchID"
      responses:
        "200":
          description: Paid settlement batch.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SettlementBatch"

  /v1/admin/settlement-batches/{settlement_batch_id}/payouts:
    get:
      tags: [admin]
      operationId: listSettlementPayouts
      summary: List settlement payout execution/proof records.
      parameters:
        - $ref: "#/components/parameters/SettlementBatchID"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Settlement payout records.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListSettlementPayoutsResponse"
    post:
      tags: [admin]
      operationId: createSettlementPayout
      summary: Request settlement payout execution.
      parameters:
        - $ref: "#/components/parameters/SettlementBatchID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSettlementPayoutRequest"
      responses:
        "202":
          description: Settlement payout execution requested.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SettlementPayoutExecutionResponse"

  /v1/admin/settlement-payouts/{settlement_payout_id}/result:
    post:
      tags: [admin]
      operationId: projectSettlementPayoutResult
      summary: Project execution-produced settlement payout proof.
      parameters:
        - name: settlement_payout_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectSettlementPayoutResultRequest"
      responses:
        "200":
          description: Settlement payout projection.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SettlementPayout"

  /v1/admin/refunds/{refund_request_id}/approve:
    post:
      tags: [admin]
      operationId: approveRefund
      summary: Approve and durably enqueue a refund in one command.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminRefundDecisionRequest"
      responses:
        "200":
          description: Refund approved and queued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminRefundDecisionResponse"

  /v1/admin/refunds/{refund_request_id}/reject:
    post:
      tags: [admin]
      operationId: rejectRefund
      summary: Admin command to reject a refund request.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminRefundDecisionRequest"
      responses:
        "200":
          description: Refund rejected; delivery access restored.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminRefundDecisionResponse"

  /v1/admin/refunds/{refund_request_id}/retry:
    post:
      tags: [admin]
      operationId: retryRefund
      summary: Re-enqueue a retryable or outcome-unknown failed refund.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AdminRefundDecisionRequest"
      responses:
        "200":
          description: Refund retry accepted and queued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AdminRefundDecisionResponse"

  /v1/admin/refunds:
    get:
      tags: [admin]
      operationId: listAdminRefunds
      summary: List refund cases across buyer accounts.
      responses:
        "200":
          description: Refund case queue.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListRefundsResponse"

  /v1/admin/refunds/{refund_request_id}:
    get:
      tags: [admin]
      operationId: getAdminRefund
      summary: Read a refund case with decisions and internal notes.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      responses:
        "200":
          description: Refund case detail.

  /v1/admin/refunds/{refund_request_id}/notes:
    post:
      tags: [admin]
      operationId: addAdminRefundNote
      summary: Add an internal note to a refund case.
      parameters:
        - $ref: "#/components/parameters/RefundRequestID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [body]
              properties:
                body:
                  type: string
      responses:
        "201":
          description: Note created.

  /v1/admin/provider-recovery-requests:
    get:
      tags: [admin]
      operationId: listProviderRecoveryRequests
      summary: List provider recovery requests and projected results.
      parameters:
        - name: provider
          in: query
          required: false
          schema:
            type: string
            enum: [alipay, wechatpay]
        - name: target_type
          in: query
          required: false
          schema:
            type: string
            enum: [payment_intent, refund_request, provider_trade]
        - name: target_id
          in: query
          required: false
          schema:
            type: string
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [requested, started, completed, failed]
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
      responses:
        "200":
          description: Provider recovery requests.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ListProviderRecoveryRequestsResponse"
    post:
      tags: [admin]
      operationId: createProviderRecoveryRequest
      summary: Admin command to query or repair provider state through backend execution.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateProviderRecoveryRequest"
      responses:
        "202":
          description: Provider recovery execution requested.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProviderRecoveryRequest"

  /v1/admin/provider-recovery-requests/{provider_recovery_request_id}/result:
    post:
      tags: [admin]
      operationId: projectProviderRecoveryResult
      summary: Project backend execution result for provider recovery.
      parameters:
        - name: provider_recovery_request_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProjectProviderRecoveryResultRequest"
      responses:
        "200":
          description: Provider recovery result projected.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProviderRecoveryRequest"

  /v1/alipay/gateway:
    get:
      tags: [provider]
      operationId: checkAlipayAppGateway
      summary: Alipay application gateway health endpoint configured in the Alipay console.
      responses:
        "200":
          description: Gateway is reachable.
          content:
            text/plain:
              schema:
                type: string
                enum: [success]
    post:
      tags: [provider]
      operationId: receiveAlipayAppGateway
      summary: Alipay application gateway endpoint configured in the Alipay console.
      responses:
        "200":
          description: Gateway notification acknowledged.
          content:
            text/plain:
              schema:
                type: string
                enum: [success]

  /v1/alipay/sandbox/notify:
    post:
      tags: [provider]
      operationId: receiveAlipaySandboxNotify
      summary: Sandbox Alipay payment notify callback.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              additionalProperties:
                type: string
      responses:
        "200":
          description: Notify route reached and acknowledged.
          content:
            text/plain:
              schema:
                type: string
                enum: [success]

  /v1/wechatpay/notify:
    post:
      tags: [provider]
      operationId: receiveWeChatPayNotify
      summary: Provider callback. Backend verifies and appends payment facts.
      requestBody:
        required: true
        content:
          application/xml:
            schema:
              type: string
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        "200":
          description: Notify accepted.
          content:
            text/plain:
              schema:
                type: string

  /v1/local-dev/payment-simulations:
    post:
      tags: [local-dev]
      operationId: createLocalDevPaymentSimulation
      summary: Local profile only. Simulates provider payment facts for tests.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateLocalDevPaymentSimulationRequest"
      responses:
        "202":
          description: Local payment simulation accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LocalDevPaymentSimulation"

  /v1/agent-device-enrollments:
    post:
      tags: [agent-identity]
      operationId: beginAgentDeviceEnrollment
      summary: Begin an Ed25519 device enrollment.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BeginAgentDeviceEnrollmentRequest"
      responses:
        "201":
          description: Enrollment challenge created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentDeviceEnrollmentChallenge"

  /v1/agent-device-enrollments/{agent_device_enrollment_id}/verify:
    post:
      tags: [agent-identity]
      operationId: verifyAgentDeviceEnrollment
      parameters:
        - name: agent_device_enrollment_id
          in: path
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VerifyAgentProofRequest"
      responses:
        "200":
          description: Device and first agent instance enrolled.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentDeviceEnrollmentVerified"

  /v1/agent-device-session-challenges:
    post:
      tags: [agent-identity]
      operationId: beginAgentDeviceSession
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BeginAgentDeviceSessionRequest"
      responses:
        "201":
          description: Device session challenge created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentDeviceSessionChallenge"

  /v1/agent-device-session-challenges/{agent_device_session_challenge_id}/verify:
    post:
      tags: [agent-identity]
      operationId: verifyAgentDeviceSession
      parameters:
        - name: agent_device_session_challenge_id
          in: path
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/VerifyAgentProofRequest"
      responses:
        "200":
          description: Renewable device session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AgentDeviceSession"

  /v1/agent-instances:
    post:
      tags: [agent-identity]
      operationId: registerAgentInstance
      security:
        - AgentDeviceSession: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [agent_type]
              properties:
                agent_type: { type: string }
      responses:
        "201":
          description: Agent instance registered on the enrolled device.

  /v1/agent-device-key-rotations:
    post:
      tags: [agent-identity]
      operationId: rotateAgentDeviceKey
      summary: Replace the authenticated device key and revoke its existing device sessions.
      security:
        - AgentDeviceSession: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [public_key]
              properties:
                public_key:
                  type: string
                  description: Base64-encoded replacement raw Ed25519 public key.
      responses:
        "201":
          description: Device key rotated; a new device session is required.
          content:
            application/json:
              schema:
                type: object
                required: [agent_device_key_id, agent_device_id, key_thumbprint, status]
                properties:
                  agent_device_key_id: { type: string }
                  agent_device_id: { type: string }
                  key_thumbprint: { type: string }
                  status: { type: string, enum: [active] }

  /v1/me/agent-devices:
    get:
      tags: [agent-identity]
      operationId: listAccountAgentDevices
      summary: List enrolled devices and agent instances bound to the current buyer account.
      responses:
        "200":
          description: Account device registry with binding provenance.
          content:
            application/json:
              schema:
                type: object
                required: [agent_devices]
                properties:
                  agent_devices:
                    type: array
                    items:
                      $ref: "#/components/schemas/AccountAgentDevice"

  /v1/me/agent-instances/{agent_instance_id}:
    delete:
      tags: [agent-identity]
      operationId: revokeAccountAgentInstance
      summary: Revoke one agent instance owned by the current buyer account.
      parameters:
        - name: agent_instance_id
          in: path
          required: true
          schema: { type: string }
      responses:
        "204":
          description: Agent instance and its active device sessions revoked.

  /v1/service-executions:
    get:
      tags: [service-execution]
      operationId: listServiceExecutions
      summary: Recover service executions visible to the authenticated device or buyer account.
      security:
        - AgentDeviceSession: []
      parameters:
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 50 }
      responses:
        "200":
          description: Recoverable service executions.
          content:
            application/json:
              schema:
                type: object
                required: [executions]
                properties:
                  executions:
                    type: array
                    items:
                      $ref: "#/components/schemas/ServiceExecutionReadModel"
    post:
      tags: [service-execution]
      operationId: startServiceExecution
      summary: Start a contract-backed service execution.
      security:
        - AgentDeviceSession: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/StartServiceExecutionRequest"
      responses:
        "201":
          description: Service execution started.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionStarted"

  /v1/service-executions/{service_execution_id}:
    get:
      tags: [service-execution]
      operationId: getServiceExecution
      summary: Read redacted service execution status and bindings.
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
      responses:
        "200":
          description: Service execution read model.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionReadModel"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/service-executions/{service_execution_id}/events:
    get:
      tags: [service-execution]
      operationId: listServiceExecutionEvents
      summary: Read redacted service execution events.
      security:
        - AgentDeviceSession: []
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
        - name: after_sequence
          in: query
          schema: { type: integer, minimum: 0, default: 0 }
        - name: limit
          in: query
          schema: { type: integer, minimum: 1, maximum: 100, default: 50 }
      responses:
        "200":
          description: Service execution event list.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionEvents"
        "404":
          $ref: "#/components/responses/NotFound"

  /v1/service-executions/{service_execution_id}/granted-result:
    get:
      tags: [service-execution, vault]
      operationId: getGrantedServiceResult
      summary: Read protected service result while a human-created agent grant is active.
      security:
        - AgentDeviceSession: []
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
      responses:
        "200":
          description: Granted service result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GrantedServiceResult"
        "403":
          description: Missing, expired, or mismatched grant.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /v1/service-executions/{service_execution_id}/capabilities/{capability_id}/invoke:
    post:
      tags: [service-execution]
      operationId: invokeServiceCapability
      summary: Invoke an agent-visible service capability.
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
        - $ref: "#/components/parameters/CapabilityID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvokeServiceCapabilityRequest"
      responses:
        "200":
          description: Capability invocation result.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceCapabilityInvoked"

  /v1/service-executions/{service_execution_id}/actions:
    post:
      tags: [service-execution]
      operationId: recordServiceExecutionAction
      summary: Record a service execution action or human handoff result.
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RecordServiceExecutionActionRequest"
      responses:
        "201":
          description: Service execution action recorded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionAction"

  /v1/service-executions/{service_execution_id}/quotes:
    post:
      tags: [service-execution]
      operationId: prepareServiceExecutionQuote
      summary: Lock one paid capability input and price without creating a Cart or Checkout.
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateServiceExecutionCheckoutRequest"
      responses:
        "201":
          description: Service quote prepared.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceQuotePrepared"

  /v1/service-executions/{service_execution_id}/checkout:
    post:
      tags: [service-execution]
      operationId: createServiceExecutionCheckout
      summary: Create a service checkout or reissue its short-lived handoff.
      parameters:
        - $ref: "#/components/parameters/ServiceExecutionID"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateServiceExecutionCheckoutRequest"
      responses:
        "201":
          description: Service checkout created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionCheckoutCreated"
        "200":
          description: Existing unpaid checkout handoff reissued without creating another checkout.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceExecutionCheckoutCreated"

components:
  securitySchemes:
    AgentDeviceSession:
      type: apiKey
      in: header
      name: Authorization
      description: Short-lived ItPayDevice session plus per-request Ed25519 proof headers.
  parameters:
    CheckoutID:
      name: checkout_id
      in: path
      required: true
      schema:
        type: string
        pattern: "^chk_"
    OrderID:
      name: order_id
      in: path
      required: true
      schema:
        type: string
        pattern: "^ord_"
    RefundRequestID:
      name: refund_request_id
      in: path
      required: true
      schema:
        type: string
        pattern: "^rr_"
    DeliveryArtifactID:
      name: delivery_artifact_id
      in: path
      required: true
      schema:
        type: string
    CatalogSnapshotID:
      name: catalog_snapshot_id
      in: path
      required: true
      schema:
        type: string
    VaultArtifactID:
      name: vault_artifact_id
      in: path
      required: true
      schema:
        type: string
    FeedbackID:
      name: feedback_id
      in: path
      required: true
      schema:
        type: string
        pattern: "^fb_"
    MerchantStatementID:
      name: merchant_statement_id
      in: path
      required: true
      schema:
        type: string
    ReconciliationRunID:
      name: reconciliation_run_id
      in: path
      required: true
      schema:
        type: string
    ReconciliationMismatchID:
      name: reconciliation_mismatch_id
      in: path
      required: true
      schema:
        type: string
    SettlementBatchID:
      name: settlement_batch_id
      in: path
      required: true
      schema:
        type: string
    DashboardAuthSessionID:
      name: dashboard_auth_session_id
      in: path
      required: true
      schema:
        type: string
    ServiceExecutionID:
      name: service_execution_id
      in: path
      required: true
      schema:
        type: string
        pattern: "^se_"
    CapabilityID:
      name: capability_id
      in: path
      required: true
      schema:
        type: string

  responses:
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"

  schemas:
    ReadyResponse:
      type: object
      required: [status, version]
      properties:
        status:
          type: string
          enum: [ready]
        version:
          type: string

    PlatformCompatibility:
      type: object
      required:
        - platform_revision
        - schema_revision
        - bootstrap_revision
        - api_contract_revision
        - minimum_cli_version
        - maximum_cli_major
      properties:
        platform_revision:
          type: string
        schema_revision:
          type: string
        bootstrap_revision:
          type: string
        api_contract_revision:
          type: string
        active_catalog_manifest_version:
          type: string
        minimum_cli_version:
          type: string
        maximum_cli_major:
          type: integer
          minimum: 1

    Money:
      type: object
      required: [amount_minor, currency]
      properties:
        amount_minor:
          type: integer
          format: int64
          minimum: 0
        currency:
          type: string
          minLength: 3
          maxLength: 3

    ProtocolProfile:
      type: object
      required: [protocol, version, status, profile]
      properties:
        protocol:
          type: string
          enum: [ucp, itpay]
        version:
          type: string
        status:
          type: string
          enum: [active, deprecated, disabled]
        profile:
          type: object
          additionalProperties: true

    CatalogManifest:
      type: object
      required: [version, status, item_count, manifest]
      properties:
        version:
          type: string
        status:
          type: string
          enum: [draft, published, superseded]
        item_count:
          type: integer
          minimum: 0
        snapshot_id:
          type: string
        manifest:
          type: object
          additionalProperties: true
        published_at:
          type: string
          format: date-time

    CatalogSnapshot:
      type: object
      required: [catalog_snapshot_id, manifest_version, snapshot_version, content_hash, snapshot]
      properties:
        catalog_snapshot_id:
          type: string
        manifest_version:
          type: string
        snapshot_version:
          type: string
        content_hash:
          type: string
        snapshot:
          type: object
          additionalProperties: true

    CatalogDelta:
      type: object
      required: [from_snapshot_version, to_snapshot_version, delta]
      properties:
        from_snapshot_version:
          type: string
        to_snapshot_version:
          type: string
        delta:
          type: object
          additionalProperties: true

    BuyerProfile:
      type: object
      required: [buyer_account_id, capabilities]
      properties:
        buyer_account_id:
          type: string
        email:
          type: string
          format: email
        phone:
          type: string
        display_name:
          type: string
        avatar_url:
          type: string
          format: uri
        delivery_contact:
          type: object
          additionalProperties: true
        capabilities:
          type: object
          required: [platform_admin]
          properties:
            platform_admin:
              type: boolean

    UpdateBuyerProfileRequest:
      type: object
      properties:
        email:
          type: string
          format: email
        phone:
          type: string
        display_name:
          type: string
        delivery_contact:
          type: object
          additionalProperties: true

    CreateCartRequest:
      type: object
      required: [items, currency]
      properties:
        currency:
          type: string
        client_context:
          type: object
          additionalProperties: true
        items:
          type: array
          minItems: 1
          items:
            type: object
            oneOf:
              - required: [service_quote_lock_id]
              - required: [catalog_item_id, catalog_variant_id, offer_id, quantity]
            properties:
              service_quote_lock_id:
                type: string
              catalog_item_id:
                type: string
              catalog_variant_id:
                type: string
              offer_id:
                type: string
              quantity:
                type: integer
                minimum: 1
              input:
                type: object
                additionalProperties: true

    AddCartItemRequest:
      type: object
      oneOf:
        - required: [service_quote_lock_id]
        - required: [catalog_item_id, catalog_variant_id, offer_id, quantity]
      properties:
        service_quote_lock_id:
          type: string
        client_context:
          type: object
          additionalProperties: true
        catalog_item_id:
          type: string
        catalog_variant_id:
          type: string
        offer_id:
          type: string
        quantity:
          type: integer
          minimum: 1
        input:
          type: object
          additionalProperties: true

    Cart:
      type: object
      required: [cart_id, status, amount_minor, currency, items]
      properties:
        cart_id:
          type: string
        order_code:
          type: string
        status:
          type: string
          enum: [active, locked, abandoned, expired]
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        items:
          type: array
          items:
            $ref: "#/components/schemas/LineItem"

    CreateCheckoutRequest:
      type: object
      required: [cart_id]
      properties:
        cart_id:
          type: string
        client_reference_id:
          type: string
        delivery_contact:
          type: object
          additionalProperties: true

    CheckoutCreated:
      type: object
      required: [checkout, checkout_url, display_token, qr_payload]
      properties:
        checkout:
          $ref: "#/components/schemas/Checkout"
        checkout_url:
          type: string
          format: uri
        display_token:
          type: string
        qr_payload:
          type: string

    Checkout:
      type: object
      required: [checkout_id, status, next_action, amount_minor, currency]
      properties:
        checkout_id:
          type: string
        order_code:
          type: string
        status:
          type: string
          enum:
            - draft
            - quote_bound
            - auth_required
            - payment_required
            - payment_pending
            - payment_succeeded
            - completed
            - failed
            - expired
            - refunded
        next_action:
          type: string
          enum:
            - open_checkout
            - authorize_buyer
            - create_payment_intent
            - wait_for_payment
            - check_email
            - none
            - contact_support
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        delivery_contact:
          type: object
          additionalProperties: true

    CheckoutPresentation:
      type: object
      required: [checkout, items, payment_intents, buyer_session]
      properties:
        checkout:
          $ref: "#/components/schemas/Checkout"
        items:
          type: array
          items:
            $ref: "#/components/schemas/LineItem"
        payment_intents:
          type: array
          items:
            $ref: "#/components/schemas/PaymentIntent"
        buyer_session:
          $ref: "#/components/schemas/BuyerSessionState"

    CreateBuyerAuthSessionRequest:
      type: object
      required: [provider, display_token]
      properties:
        provider:
          type: string
          enum: [alipay, wechat]
        display_token:
          type: string

    BuyerAuthSession:
      type: object
      required: [buyer_auth_session_id, status, provider, provider_auth_url]
      properties:
        buyer_auth_session_id:
          type: string
        status:
          type: string
          enum: [created, waiting_provider, completed, expired, failed]
        provider:
          type: string
        provider_auth_url:
          type: string
          format: uri
        dashboard_auth_session_id:
          type: string
        start_token:
          type: string

    CompleteBuyerAuthWithAlipayCodeRequest:
      type: object
      required: [display_token, auth_code]
      properties:
        display_token:
          type: string
        auth_code:
          type: string
        scope:
          type: string
          default: auth_user
        source:
          type: string
          example: alipay_js_bridge

    CompleteCheckoutExchangeRequest:
      type: object
      required: [display_token]
      properties:
        display_token:
          type: string
          description: One-time display token issued at checkout creation. Must have purpose=complete_exchange.

    CompleteCheckoutExchangeResponse:
      type: object
      required: [order_id, buyer_session]
      properties:
        order_id:
          type: string
        buyer_session:
          $ref: "#/components/schemas/CompleteExchangeBuyerSession"

    ReceiptExchangeRequest:
      type: object
      required: [receipt_token, client_binding_secret]
      properties:
        receipt_token:
          type: string
          description: Signed one-time token from the payment receipt email.
        client_binding_secret:
          type: string
          minLength: 16
          description: Browser-generated secret that prevents replay from another browser.

    ReceiptExchangeResponse:
      type: object
      required: [order_id, session_token, scope, expires_at]
      properties:
        order_id:
          type: string
        session_token:
          type: string
        scope:
          type: string
          enum: [order]
        expires_at:
          type: string
          format: date-time

    OrderDeliveryAccess:
      type: object
      required:
        - order_id
        - status
        - delivery_mode
      properties:
        order_id:
          type: string
        service_execution_id:
          type: string
        delivery_artifact_id:
          type: string
        vault_artifact_id:
          type: string
        status:
          type: string
        delivery_mode:
          type: string
          enum: [agent_visible_result, vault_artifact]
        delivery_url:
          type: string
          format: uri-reference

    OwnerDeliveryRedemption:
      type: object
      required: [session_token, scope, expires_at, order_id, delivery_artifact_id, vault_artifact_id]
      properties:
        session_token:
          type: string
        scope:
          type: string
          enum: [order]
        expires_at:
          type: string
          format: date-time
        order_id:
          type: string
        delivery_artifact_id:
          type: string
        vault_artifact_id:
          type: string

    CompleteExchangeBuyerSession:
      type: object
      required: [session_token, scope, expires_at, was_upgraded]
      properties:
        session_token:
          type: string
        scope:
          type: string
          enum: [account]
        buyer_account_id:
          type: string
        expires_at:
          type: string
          format: date-time
        was_upgraded:
          type: boolean

    CreatePaymentIntentRequest:
      type: object
      required: [payment_method_type, display_token]
      properties:
        payment_method_type:
          type: string
          enum: [alipay, wechatpay]
        display_token:
          type: string
        refresh_action:
          type: boolean

    PaymentIntent:
      type: object
      required: [payment_intent_id, checkout_id, status, payment_method_type, amount_minor, currency]
      properties:
        payment_intent_id:
          type: string
        checkout_id:
          type: string
        status:
          type: string
          enum:
            - requires_action
            - waiting_user_payment
            - verified
            - failed
            - expired
            - partially_refunded
            - refunded
        payment_method_type:
          type: string
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        action:
          $ref: "#/components/schemas/PaymentAction"

    PaymentAction:
      type: object
      properties:
        qr_image_url:
          type: string
          format: uri
        mobile_wallet_url:
          type: string
          format: uri

    ServiceCapability:
      type: object
      required: [capability_id, phase, agent_visible, requires_payment, requires_human_action, vault_required, delivery_email_required]
      properties:
        capability_id:
          type: string
        phase:
          type: string
          enum: [pre_purchase, paid_fulfillment, post_purchase]
        agent_visible:
          type: boolean
        requires_payment:
          type: boolean
        requires_human_action:
          type: boolean
        vault_required:
          type: boolean
        delivery_email_required:
          type: boolean
        price_amount_minor:
          type: integer
          format: int64
          minimum: 0
        price_currency:
          type: string
        free_quota_limit:
          type: integer
          minimum: 0
        quota_subject:
          type: string
        input_schema:
          type: object
          additionalProperties: true
        output_schema:
          type: object
          additionalProperties: true

    ServiceExecution:
      type: object
      required:
        - service_execution_id
        - service_id
        - service_contract_version_id
        - status
        - phase
        - checkout_required
        - next_action
        - started_at
        - created_at
        - updated_at
      properties:
        service_execution_id:
          type: string
        service_id:
          type: string
        service_contract_version_id:
          type: string
        compiled_service_graph_id:
          type: string
        buyer_id:
          type: string
        agent_device_id:
          type: string
        status:
          type: string
        phase:
          type: string
        current_capability_id:
          type: string
        checkout_required:
          type: boolean
        next_action:
          type: string
        client_context:
          type: object
          additionalProperties: true
        started_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
        failed_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    StartServiceExecutionRequest:
      type: object
      required: [service_id]
      properties:
        service_id:
          type: string
        client_context:
          type: object
          additionalProperties: true

    ServiceExecutionStarted:
      type: object
      required: [execution, capabilities]
      properties:
        execution:
          $ref: "#/components/schemas/ServiceExecution"
        capabilities:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCapability"
        graph_id:
          type: string

    InvokeServiceCapabilityRequest:
      type: object
      properties:
        idempotency_key:
          type: string
        redacted_summary:
          type: object
          additionalProperties: true

    ServiceCapabilityInvocation:
      type: object
      required: [service_capability_invocation_id, service_execution_id, capability_id, status, created_at]
      properties:
        service_capability_invocation_id:
          type: string
        service_execution_id:
          type: string
        capability_id:
          type: string
        provider_key:
          type: string
        idempotency_key_id:
          type: string
        status:
          type: string
        safe_result_preview:
          type: object
          additionalProperties: true
        response_hash:
          type: string
        response_ref:
          type: string
        error_code:
          type: string
        error_message:
          type: string
        created_at:
          type: string
          format: date-time

    ServiceCapabilityResultItem:
      type: object
      required: [service_capability_result_item_id, service_execution_id, capability_id, rank, display_title, safe_payload, created_at]
      properties:
        service_capability_result_item_id:
          type: string
        service_capability_invocation_id:
          type: string
        service_execution_id:
          type: string
        capability_id:
          type: string
        rank:
          type: integer
        display_title:
          type: string
        safe_payload:
          type: object
          additionalProperties: true
        created_at:
          type: string
          format: date-time

    ServiceCapabilityInvoked:
      type: object
      required: [execution, result_items, provider_called]
      properties:
        execution:
          $ref: "#/components/schemas/ServiceExecution"
        invocation:
          $ref: "#/components/schemas/ServiceCapabilityInvocation"
        result_items:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCapabilityResultItem"
        provider_called:
          type: boolean
          description: Whether this request reached the external provider.
        effective_quota:
          $ref: "#/components/schemas/EffectiveQuota"
        next_actions:
          type: array
          items:
            $ref: "#/components/schemas/ServiceExecutionNextAction"

    EffectiveQuota:
      type: object
      required: [bucket, subject_type, limit, remaining, exhausted, replenishment]
      properties:
        bucket: { type: string }
        subject_type: { type: string, enum: [device_lineage, buyer_account] }
        limit: { type: integer, minimum: 0 }
        remaining: { type: integer, minimum: 0 }
        exhausted: { type: boolean }
        replenishment: { type: string }

    ServiceExecutionNextAction:
      type: object
      required: [kind, requires_human]
      properties:
        kind: { type: string, enum: [create_checkout] }
        capability_id: { type: string }
        requires_human: { type: boolean }

    RecordServiceExecutionActionRequest:
      type: object
      required: [action_type]
      properties:
        action_type:
          type: string
        actor_type:
          type: string
        actor_id:
          type: string
        status:
          type: string
        input_snapshot:
          type: object
          additionalProperties: true
        result_snapshot:
          type: object
          additionalProperties: true
        result_item_id:
          type: string
        required_before:
          type: string

    ServiceExecutionAction:
      allOf:
        - $ref: "#/components/schemas/RecordServiceExecutionActionRequest"
        - type: object
          required: [service_execution_action_id, service_execution_id, status, actor_type]
          properties:
            service_execution_action_id:
              type: string
            service_execution_id:
              type: string

    CreateServiceExecutionCheckoutRequest:
      type: object
      properties:
        capability_id:
          type: string
        delivery_contact:
          type: object
          additionalProperties: true
        locked_input:
          type: object
          additionalProperties: true
        resume:
          type: boolean
          description: Reissue the existing checkout handoff; capability and delivery contact are read from owner facts.

    ServiceCheckoutBinding:
      type: object
      required: [service_checkout_binding_id, service_execution_id, service_quote_lock_id, checkout_id, status]
      properties:
        service_checkout_binding_id:
          type: string
        service_execution_id:
          type: string
        service_quote_lock_id:
          type: string
        checkout_id:
          type: string
        status:
          type: string

    ServiceExecutionCheckoutCreated:
      type: object
      required: [service_quote_lock_id, capability_id, locked_input, cart, checkout, binding, handoff_reissued]
      properties:
        service_quote_lock_id:
          type: string
        capability_id:
          type: string
          description: Logical capability ID from the locked service contract, not an internal database record ID.
        locked_input:
          type: object
          additionalProperties: true
          description: Final policy-resolved input protected by the quote lock.
        cart:
          $ref: "#/components/schemas/Cart"
        handoff_reissued:
          type: boolean
        checkout:
          $ref: "#/components/schemas/CheckoutCreated"
        binding:
          $ref: "#/components/schemas/ServiceCheckoutBinding"

    ServiceQuotePrepared:
      type: object
      required: [service_quote_lock_id, service_execution_id, capability_id, amount_minor, currency, expires_at]
      properties:
        service_quote_lock_id: { type: string }
        service_execution_id: { type: string }
        capability_id: { type: string }
        amount_minor: { type: integer, format: int64 }
        currency: { type: string }
        expires_at: { type: string, format: date-time }

    ServiceExecutionEvent:
      type: object
      required: [service_execution_event_id, service_execution_id, sequence, type, status, phase, occurred_at]
      properties:
        service_execution_event_id:
          type: string
        service_execution_id:
          type: string
        sequence:
          type: integer
          format: int64
        type:
          type: string
        status:
          type: string
        phase:
          type: string
        capability_id:
          type: string
        redacted_summary:
          type: object
          additionalProperties: true
        occurred_at:
          type: string
          format: date-time

    ServiceExecutionEvents:
      type: object
      required: [events]
      properties:
        events:
          type: array
          items:
            $ref: "#/components/schemas/ServiceExecutionEvent"

    ServiceExecutionReadModel:
      type: object
      required: [execution, capabilities, events, result_items, actions, checkout_bindings, payment_bindings, execution_requests, provider_invocations, delivery_bindings, refunds, current_result_items, allowed_actions]
      properties:
        execution:
          $ref: "#/components/schemas/ServiceExecution"
        capabilities:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCapability"
        events:
          type: array
          items:
            $ref: "#/components/schemas/ServiceExecutionEvent"
        result_items:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCapabilityResultItem"
        actions:
          type: array
          items:
            $ref: "#/components/schemas/ServiceExecutionAction"
        checkout_bindings:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCheckoutBinding"
        payment_bindings:
          type: array
          items:
            type: object
            additionalProperties: true
        execution_requests:
          type: array
          items:
            type: object
            additionalProperties: true
        provider_invocations:
          type: array
          items:
            type: object
            additionalProperties: true
        delivery_bindings:
          type: array
          items:
            type: object
            additionalProperties: true
        current_delivery:
          type: object
          description: Current effective delivery selected by the backend for the execution's active capability; delivery_bindings remains the history.
          additionalProperties: true
        refunds:
          type: array
          items:
            $ref: "#/components/schemas/RefundRequest"
        current_result_items:
          type: array
          items:
            $ref: "#/components/schemas/ServiceCapabilityResultItem"
        allowed_actions:
          type: array
          items:
            $ref: "#/components/schemas/ServiceExecutionAllowedAction"

    ServiceExecutionAllowedAction:
      type: object
      required: [type, requires_human]
      properties:
        type:
          type: string
          enum: [invoke_capability, select_candidate, prepare_quote, resume_checkout, wait, view_delivery]
        capability_id: { type: string }
        source_capability_id: { type: string }
        requires_human: { type: boolean }

    ServiceFeedback:
      type: object
      required: [feedback_id, order_item_id, submitter_kind, rating, status, created_at, updated_at]
      properties:
        feedback_id:
          type: string
          pattern: "^fb_"
        order_item_id:
          type: string
        submitter_kind:
          type: string
          enum: [buyer, agent]
        rating:
          type: integer
          minimum: 1
          maximum: 5
        note:
          type: string
        status:
          type: string
          enum: [new, acknowledged, resolved, dismissed]
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    SubmitServiceFeedbackRequest:
      type: object
      required: [order_item_id, rating]
      properties:
        order_item_id:
          type: string
        rating:
          type: integer
          minimum: 1
          maximum: 5
        note:
          type: string
          maxLength: 2000

    AdminServiceFeedback:
      allOf:
        - $ref: "#/components/schemas/ServiceFeedback"
        - type: object
          required: [order_id]
          properties:
            order_id:
              type: string
              pattern: "^ord_"
            submitter_account_id:
              type: string
            agent_instance_id:
              type: string
            admin_note:
              type: string
            resolved_by_admin_id:
              type: string
            resolved_at:
              type: string
              format: date-time

    SubmitServiceFeedbackResponse:
      type: object
      required: [feedback]
      properties:
        feedback:
          $ref: "#/components/schemas/ServiceFeedback"

    ListServiceFeedbackResponse:
      type: object
      required: [feedbacks, total]
      properties:
        feedbacks:
          type: array
          items:
            $ref: "#/components/schemas/ServiceFeedback"
        total:
          type: integer
          format: int64

    ListAdminServiceFeedbackResponse:
      type: object
      required: [feedbacks, total]
      properties:
        feedbacks:
          type: array
          items:
            $ref: "#/components/schemas/AdminServiceFeedback"
        total:
          type: integer
          format: int64

    GetAdminServiceFeedbackResponse:
      type: object
      required: [feedback]
      properties:
        feedback:
          $ref: "#/components/schemas/AdminServiceFeedback"

    AdminUpdateServiceFeedbackRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [new, acknowledged, resolved, dismissed]
        admin_note:
          type: string

    AdminUpdateServiceFeedbackResponse:
      type: object
      required: [feedback]
      properties:
        feedback:
          $ref: "#/components/schemas/AdminServiceFeedback"

    DashboardAuthSession:
      type: object
      required: [dashboard_auth_session_id, status, provider]
      properties:
        dashboard_auth_session_id:
          type: string
        status:
          type: string
          enum: [created, waiting_provider, completed, expired, failed]
        provider:
          type: string
        start_url:
          type: string
          format: uri
        poll_token:
          type: string

    BuyerSession:
      type: object
      required: [buyer_session_id, scope, expires_at]
      properties:
        buyer_session_id:
          type: string
        scope:
          type: string
          enum: [account, order, checkout]
        expires_at:
          type: string
          format: date-time
        session_token:
          type: string

    BuyerSessionState:
      type: object
      required: [state]
      properties:
        state:
          type: string
          enum: [anonymous, checkout_scoped, account]
        display_name:
          type: string
        avatar_url:
          type: string
          format: uri

    ListOrdersResponse:
      type: object
      required: [orders]
      properties:
        orders:
          type: array
          items:
            $ref: "#/components/schemas/Order"
        next_cursor:
          type: string

    Order:
      type: object
      required: [order_id, checkout_id, status, amount_minor, currency, created_at, items, delivery_artifacts]
      properties:
        order_id:
          type: string
        order_code:
          type: string
        checkout_id:
          type: string
        status:
          type: string
          enum:
            - pending_payment
            - paid
            - delivery_pending
            - delivered
            - failed
            - partially_refunded
            - refunded
            - cancelled
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        created_at:
          type: string
          format: date-time
        paid_at:
          type: string
          format: date-time
        items:
          type: array
          items:
            $ref: "#/components/schemas/LineItem"
        delivery_artifacts:
          type: array
          items:
            $ref: "#/components/schemas/DeliveryArtifact"
        receipt_proof:
          type: object
          required: [algorithm, key_id, jws, public_key_jwk]
          properties:
            algorithm:
              type: string
              enum: [EdDSA]
            key_id:
              type: string
            jws:
              type: string
              description: Compact JWS over the order JSON before receipt_proof is attached.
            public_key_jwk:
              type: object
              additionalProperties:
                type: string

    LineItem:
      type: object
      required: [title, quantity, amount_minor, currency]
      properties:
        line_item_id:
          type: string
        cart_item_id:
          type: string
        checkout_item_id:
          type: string
        catalog_item_id:
          type: string
        catalog_variant_id:
          type: string
        offer_id:
          type: string
        service_execution_id:
          type: string
        service_quote_lock_id:
          type: string
        service_capability_id:
          type: string
        next_action:
          type: string
        checkout_required:
          type: boolean
        agent_identity_required:
          type: boolean
        title:
          type: string
        quantity:
          type: integer
          minimum: 1
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        input:
          type: object
          additionalProperties: true

    DeliveryArtifact:
      type: object
      required: [delivery_artifact_id, order_id, status, artifact_type, sensitive_content_redacted]
      properties:
        delivery_artifact_id:
          type: string
        order_id:
          type: string
        order_item_id:
          type: string
        vault_artifact_id:
          type: string
        notification_status:
          type: string
          enum: [pending, sent, failed, suppressed]
        status:
          type: string
          enum: [not_required, pending, claimable, sent, claimed, failed, revoked]
        artifact_type:
          type: string
        public_preview:
          type: string
        sensitive_content_redacted:
          type: boolean

    ClaimDeliveryExchangeRequest:
      type: object
      required: [claim_token]
      properties:
        claim_token:
          type: string

    ClaimDeliveryExchangeResponse:
      type: object
      required: [buyer_session_id, scope, expires_at, session_token, order_id, delivery_artifact_id, vault_artifact_id, claim_link_id]
      properties:
        buyer_session_id:
          type: string
        scope:
          type: string
          enum: [order]
        expires_at:
          type: string
          format: date-time
        session_token:
          type: string
        order_id:
          type: string
        delivery_artifact_id:
          type: string
        vault_artifact_id:
          type: string
        claim_link_id:
          type: string

    VaultArtifact:
      type: object
      required: [vault_artifact_id, order_id, status, redacted_preview]
      properties:
        vault_artifact_id:
          type: string
        order_id:
          type: string
        delivery_artifact_id:
          type: string
        status:
          type: string
          enum: [sealed, revealable, revealed, revoked]
        schema:
          type: object
          additionalProperties: true
        redacted_preview:
          type: object
          additionalProperties: true
        revealed_payload:
          type: object
          additionalProperties: true

    BeginAgentDeviceEnrollmentRequest:
      type: object
      required: [public_key, agent_type]
      properties:
        public_key:
          type: string
          description: Base64-encoded raw Ed25519 public key.
        agent_type:
          type: string
          enum: [codex-desktop, codex-cli, claude-code-desktop, claude-code-cli, workbuddy, kimi-code, openclaw, hermes]

    VerifyAgentProofRequest:
      type: object
      required: [challenge, signature]
      properties:
        challenge: { type: string }
        signature:
          type: string
          description: Base64 Ed25519 signature over the documented canonical challenge envelope.

    AgentDeviceEnrollmentChallenge:
      type: object
      required: [agent_device_enrollment_id, challenge, expires_at]
      properties:
        agent_device_enrollment_id: { type: string }
        challenge: { type: string }
        expires_at: { type: string, format: date-time }

    AgentDeviceEnrollmentVerified:
      type: object
      required: [agent_device_id, agent_device_key_id, quota_lineage_id, agent_instance_id, agent_type]
      properties:
        agent_device_id: { type: string }
        agent_device_key_id: { type: string }
        quota_lineage_id: { type: string }
        agent_instance_id: { type: string }
        agent_type: { type: string }

    BeginAgentDeviceSessionRequest:
      type: object
      required: [agent_device_id, agent_instance_id]
      properties:
        agent_device_id: { type: string }
        agent_instance_id: { type: string }

    AgentDeviceSessionChallenge:
      type: object
      required: [agent_device_session_challenge_id, challenge, expires_at]
      properties:
        agent_device_session_challenge_id: { type: string }
        challenge: { type: string }
        expires_at: { type: string, format: date-time }

    AgentDeviceSession:
      type: object
      required: [session_token, expires_at]
      properties:
        session_token: { type: string }
        expires_at: { type: string, format: date-time }

    AccountAgentInstance:
      type: object
      required: [agent_instance_id, agent_type, status, first_seen_at, last_seen_at]
      properties:
        agent_instance_id: { type: string }
        agent_type: { type: string }
        display_name: { type: string }
        status: { type: string, enum: [active, revoked] }
        first_seen_at: { type: string, format: date-time }
        last_seen_at: { type: string, format: date-time }
        revoked_at: { type: string, format: date-time }

    AccountAgentDevice:
      type: object
      required: [agent_device_id, quota_lineage_id, trust_status, status, binding_id, bound_at, agent_instances]
      properties:
        agent_device_id: { type: string }
        quota_lineage_id: { type: string }
        trust_status: { type: string }
        status: { type: string }
        enrolled_at: { type: string, format: date-time }
        last_seen_at: { type: string, format: date-time }
        binding_id: { type: string }
        source_order_id: { type: string }
        source_payment_proof_id: { type: string }
        bound_at: { type: string, format: date-time }
        agent_instances:
          type: array
          items:
            $ref: "#/components/schemas/AccountAgentInstance"

    CreateAgentReadGrantRequest:
      type: object
      required: [grant_scope]
      properties:
        grant_scope:
          type: object
          additionalProperties: true

    AgentReadGrant:
      type: object
      required: [agent_read_grant_id, vault_artifact_id, order_id, status, grant_scope]
      properties:
        agent_read_grant_id:
          type: string
        vault_artifact_id:
          type: string
        order_id:
          type: string
        status:
          type: string
          enum: [pending, active, revoked, expired]
        grant_scope:
          type: object
          additionalProperties: true
        expires_at:
          type: string
          format: date-time

    GrantedServiceResult:
      type: object
      required: [service_execution_id, vault_artifact_id, agent_read_grant_id, grant_status, result]
      properties:
        service_execution_id:
          type: string
        vault_artifact_id:
          type: string
        agent_read_grant_id:
          type: string
        grant_status:
          type: string
          enum: [active]
        expires_at:
          type: string
          format: date-time
        result:
          type: object
          additionalProperties: true

    CreateRefundRequest:
      type: object
      required: [reason]
      properties:
        reason:
          type: string
        order_item_id:
          type: string

    RefundRequest:
      type: object
      required: [refund_request_id, order_id, status, amount_minor, currency, created_at]
      properties:
        refund_request_id:
          type: string
        order_id:
          type: string
        order_item_id:
          type: string
        status:
          type: string
          enum:
            - requested
            - policy_review_required
            - accepted
            - provider_pending
            - succeeded
            - failed
            - cancelled
            - rejected
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        reason:
          type: string
        decision_mode:
          type: string
          enum: [automatic, manual]
        consumption_state:
          type: string
          enum: [unconsumed, consumed, unknown]
        failure_class:
          type: string
          enum: [known_no_effect, retryable, outcome_unknown, permanent]
        access_locked:
          type: boolean
        can_cancel:
          type: boolean
        created_at:
          type: string
          format: date-time

    ListRefundsResponse:
      type: object
      required: [refunds]
      properties:
        refunds:
          type: array
          items:
            $ref: "#/components/schemas/RefundRequest"

    AdminRefundDecisionRequest:
      type: object
      properties:
        reason:
          type: string

    AdminRefundDecisionResponse:
      type: object
      required: [refund]
      properties:
        refund:
          $ref: "#/components/schemas/RefundRequest"

    ListMerchantStatementsResponse:
      type: object
      required: [statements]
      properties:
        statements:
          type: array
          items:
            $ref: "#/components/schemas/MerchantStatementSummary"

    MerchantStatementSummary:
      type: object
      required: [merchant_statement_id, status, period_start, period_end, currency, total_amount_minor]
      properties:
        merchant_statement_id:
          type: string
        status:
          type: string
          enum: [generated, published, voided]
        period_start:
          type: string
          format: date
        period_end:
          type: string
          format: date
        currency:
          type: string
        total_amount_minor:
          type: integer
          format: int64

    MerchantStatement:
      allOf:
        - $ref: "#/components/schemas/MerchantStatementSummary"
        - type: object
          required: [lines]
          properties:
            lines:
              type: array
              items:
                $ref: "#/components/schemas/MerchantStatementLine"

    MerchantStatementExport:
      type: object
      required: [merchant_statement_export_id, merchant_statement_id, format, file_ref, file_hash, generated_at]
      properties:
        merchant_statement_export_id:
          type: string
        merchant_statement_id:
          type: string
        format:
          type: string
          enum: [pdf, csv, json]
        file_ref:
          type: string
        file_hash:
          type: string
        generated_at:
          type: string
          format: date-time

    CreateMerchantStatementExportRequest:
      type: object
      required: [format, file_ref, file_hash]
      properties:
        format:
          type: string
          enum: [pdf, csv, json]
        file_ref:
          type: string
        file_hash:
          type: string

    ListMerchantStatementExportsResponse:
      type: object
      required: [exports]
      properties:
        exports:
          type: array
          items:
            $ref: "#/components/schemas/MerchantStatementExport"

    MerchantStatementLine:
      type: object
      required: [merchant_statement_line_id, line_type, amount_minor, currency]
      properties:
        merchant_statement_line_id:
          type: string
        line_type:
          type: string
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        description:
          type: string

    LedgerEntry:
      type: object
      required: [ledger_entry_id, account_type, direction, amount_minor, currency, occurred_at]
      properties:
        ledger_entry_id:
          type: string
        order_id:
          type: string
        payment_intent_id:
          type: string
        refund_request_id:
          type: string
        merchant_id:
          type: string
        account_type:
          type: string
        direction:
          type: string
          enum: [debit, credit]
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string
        occurred_at:
          type: string
          format: date-time
        metadata:
          type: object
          additionalProperties: true

    ListLedgerEntriesResponse:
      type: object
      required: [ledger_entries]
      properties:
        ledger_entries:
          type: array
          items:
            $ref: "#/components/schemas/LedgerEntry"

    ProviderStatementImport:
      type: object
      required: [provider_statement_import_id, provider, status, line_count, imported_at]
      properties:
        provider_statement_import_id:
          type: string
        provider:
          type: string
        status:
          type: string
          enum: [imported, parsed, failed, reconciled]
        line_count:
          type: integer
          minimum: 0
        imported_at:
          type: string
          format: date-time

    CreateProviderStatementImportRequest:
      type: object
      required: [provider, file_hash]
      properties:
        provider:
          type: string
          enum: [alipay, wechatpay]
        file_hash:
          type: string
        line_count:
          type: integer
          minimum: 0

    ListProviderStatementImportsResponse:
      type: object
      required: [imports]
      properties:
        imports:
          type: array
          items:
            $ref: "#/components/schemas/ProviderStatementImport"

    ProviderStatementLine:
      type: object
      required:
        - provider_statement_line_id
        - provider_statement_import_id
        - provider
        - amount_minor
        - currency
        - raw_line_hash
      properties:
        provider_statement_line_id:
          type: string
        provider_statement_import_id:
          type: string
        provider:
          type: string
          enum: [alipay, wechatpay]
        provider_trade_no:
          type: string
        provider_refund_id:
          type: string
        amount_minor:
          type: integer
          format: int64
          minimum: 0
        currency:
          type: string
        occurred_at:
          type: string
          format: date-time
        raw_line_hash:
          type: string
        raw_line_ref:
          type: string

    ImportProviderStatementLinesRequest:
      type: object
      required: [lines]
      properties:
        lines:
          type: array
          minItems: 1
          maxItems: 500
          items:
            type: object
            required: [provider, amount_minor, currency, raw_line_hash]
            properties:
              provider:
                type: string
                enum: [alipay, wechatpay]
              provider_trade_no:
                type: string
              provider_refund_id:
                type: string
              amount_minor:
                type: integer
                format: int64
                minimum: 0
              currency:
                type: string
              occurred_at:
                type: string
                format: date-time
              raw_line_hash:
                type: string
              raw_line_ref:
                type: string

    ListProviderStatementLinesResponse:
      type: object
      required: [lines]
      properties:
        lines:
          type: array
          items:
            $ref: "#/components/schemas/ProviderStatementLine"

    MerchantKYBCase:
      type: object
      required: [kyb_case_id, merchant_id, status, created_at, updated_at]
      properties:
        kyb_case_id:
          type: string
        merchant_id:
          type: string
        status:
          type: string
          enum: [draft, submitted, approved, rejected, expired]
        risk_level:
          type: string
          enum: [low, medium, high]
        submitted_at:
          type: string
          format: date-time
        decided_at:
          type: string
          format: date-time
        decision_reason:
          type: string
        evidence_ref:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    CreateMerchantKYBCaseRequest:
      type: object
      required: [merchant_id]
      properties:
        merchant_id:
          type: string
        evidence_ref:
          type: string

    UpdateMerchantKYBCaseRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [submitted, approved, rejected, expired]
        risk_level:
          type: string
          enum: [low, medium, high]
        decision_reason:
          type: string

    ListMerchantKYBCasesResponse:
      type: object
      required: [cases]
      properties:
        cases:
          type: array
          items:
            $ref: "#/components/schemas/MerchantKYBCase"

    PolicyDecision:
      type: object
      required:
        - policy_decision_id
        - subject_type
        - subject_id
        - decision
        - policy_name
        - policy_version
        - decided_by
        - decided_at
      properties:
        policy_decision_id:
          type: string
        subject_type:
          type: string
        subject_id:
          type: string
        decision:
          type: string
          enum: [allow, deny, review]
        policy_name:
          type: string
        policy_version:
          type: string
        reason_code:
          type: string
        snapshot:
          type: object
          additionalProperties: true
        decided_by:
          type: string
        decided_at:
          type: string
          format: date-time

    UpdateMerchantKYBCaseResponse:
      type: object
      required: [case]
      properties:
        case:
          $ref: "#/components/schemas/MerchantKYBCase"
        policy_decision:
          $ref: "#/components/schemas/PolicyDecision"

    ListPolicyDecisionsResponse:
      type: object
      required: [policy_decisions]
      properties:
        policy_decisions:
          type: array
          items:
            $ref: "#/components/schemas/PolicyDecision"

    ReconciliationRun:
      type: object
      required: [reconciliation_run_id, status, started_by, started_at]
      properties:
        reconciliation_run_id:
          type: string
        provider_statement_import_id:
          type: string
        status:
          type: string
          enum: [running, completed, failed]
        started_by:
          type: string
        started_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time

    ListReconciliationRunsResponse:
      type: object
      required: [runs]
      properties:
        runs:
          type: array
          items:
            $ref: "#/components/schemas/ReconciliationRun"

    CreateReconciliationRunRequest:
      type: object
      properties:
        provider_statement_import_id:
          type: string

    ReconciliationMismatch:
      type: object
      required: [reconciliation_mismatch_id, reconciliation_run_id, mismatch_type, status]
      properties:
        reconciliation_mismatch_id:
          type: string
        reconciliation_run_id:
          type: string
        mismatch_type:
          type: string
        status:
          type: string
          enum: [open, proposed, resolved, ignored]
        provider_statement_line_id:
          type: string
        ledger_entry_id:
          type: string
        amount_delta_minor:
          type: integer
          format: int64
        currency:
          type: string

    ReconciliationMatch:
      type: object
      required:
        - reconciliation_match_id
        - reconciliation_run_id
        - provider_statement_line_id
        - ledger_entry_id
        - match_type
      properties:
        reconciliation_match_id:
          type: string
        reconciliation_run_id:
          type: string
        provider_statement_line_id:
          type: string
        ledger_entry_id:
          type: string
        match_type:
          type: string

    ProjectReconciliationResultRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [completed, failed]
        mismatches:
          type: array
          maxItems: 500
          items:
            type: object
            required: [mismatch_type]
            properties:
              mismatch_type:
                type: string
              provider_statement_line_id:
                type: string
              ledger_entry_id:
                type: string
              amount_delta_minor:
                type: integer
                format: int64
              currency:
                type: string
        matches:
          type: array
          maxItems: 500
          items:
            type: object
            required: [provider_statement_line_id, ledger_entry_id, match_type]
            properties:
              provider_statement_line_id:
                type: string
              ledger_entry_id:
                type: string
              match_type:
                type: string

    ReconciliationProjectionResult:
      type: object
      required: [run, mismatches, matches]
      properties:
        run:
          $ref: "#/components/schemas/ReconciliationRun"
        mismatches:
          type: array
          items:
            $ref: "#/components/schemas/ReconciliationMismatch"
        matches:
          type: array
          items:
            $ref: "#/components/schemas/ReconciliationMatch"

    UpdateReconciliationMismatchRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [resolved, ignored]

    ListReconciliationMismatchesResponse:
      type: object
      required: [mismatches]
      properties:
        mismatches:
          type: array
          items:
            $ref: "#/components/schemas/ReconciliationMismatch"

    SettlementBatch:
      type: object
      required: [settlement_batch_id, merchant_id, status, currency, total_amount_minor]
      properties:
        settlement_batch_id:
          type: string
        merchant_id:
          type: string
        status:
          type: string
          enum: [draft, finalized, paid, cancelled]
        currency:
          type: string
        total_amount_minor:
          type: integer
          format: int64
        finalized_at:
          type: string
          format: date-time

    ListSettlementBatchesResponse:
      type: object
      required: [settlement_batches]
      properties:
        settlement_batches:
          type: array
          items:
            $ref: "#/components/schemas/SettlementBatch"

    SettlementPayout:
      type: object
      required: [settlement_payout_id, settlement_batch_id, provider, status, requested_by, requested_at]
      properties:
        settlement_payout_id:
          type: string
        settlement_batch_id:
          type: string
        provider:
          type: string
          enum: [alipay, wechatpay, bank_transfer]
        status:
          type: string
          enum: [requested, submitted, paid, failed]
        destination_ref:
          type: string
        payout_ref:
          type: string
        proof_ref:
          type: string
        proof_hash:
          type: string
        requested_by:
          type: string
        requested_at:
          type: string
          format: date-time
        submitted_at:
          type: string
          format: date-time
        paid_at:
          type: string
          format: date-time

    ListSettlementPayoutsResponse:
      type: object
      required: [payouts]
      properties:
        payouts:
          type: array
          items:
            $ref: "#/components/schemas/SettlementPayout"

    CreateSettlementPayoutRequest:
      type: object
      required: [provider]
      properties:
        provider:
          type: string
          enum: [alipay, wechatpay, bank_transfer]
        destination_ref:
          type: string

    SettlementPayoutExecutionResponse:
      type: object
      required: [payout, execution_request]
      properties:
        payout:
          $ref: "#/components/schemas/SettlementPayout"
        execution_request:
          $ref: "#/components/schemas/ExecutionRequest"

    ProjectSettlementPayoutResultRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [paid, failed]
        payout_ref:
          type: string
        proof_ref:
          type: string
        proof_hash:
          type: string
        paid_at:
          type: string
          format: date-time

    CreateProviderRecoveryRequest:
      type: object
      required: [provider, target_type, target_id, action]
      properties:
        provider:
          type: string
          enum: [alipay, wechatpay]
        target_type:
          type: string
          enum: [payment_intent, refund_request, provider_trade]
        target_id:
          type: string
        action:
          type: string
          enum: [query, repair, reconcile]
        reason:
          type: string

    ProviderRecoveryRequest:
      type: object
      required: [provider_recovery_request_id, provider, target_type, target_id, action, status, requested_by, requested_at]
      properties:
        provider_recovery_request_id:
          type: string
        provider:
          type: string
        target_type:
          type: string
        target_id:
          type: string
        action:
          type: string
        status:
          type: string
          enum: [requested, started, completed, failed]
        reason:
          type: string
        result_ref:
          type: string
        result_hash:
          type: string
        summary:
          type: string
        requested_by:
          type: string
        requested_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
        execution_request:
          $ref: "#/components/schemas/ExecutionRequest"

    ListProviderRecoveryRequestsResponse:
      type: object
      required: [requests]
      properties:
        requests:
          type: array
          items:
            $ref: "#/components/schemas/ProviderRecoveryRequest"

    ProjectProviderRecoveryResultRequest:
      type: object
      required: [status]
      properties:
        status:
          type: string
          enum: [completed, failed]
        result_ref:
          type: string
        result_hash:
          type: string
        summary:
          type: string

    CreateLocalDevPaymentSimulationRequest:
      type: object
      required: [payment_intent_id, provider_status]
      properties:
        payment_intent_id:
          type: string
        provider_status:
          type: string
          enum: [paid, failed, expired]
        amount_minor:
          type: integer
          format: int64
        currency:
          type: string

    LocalDevPaymentSimulation:
      type: object
      required: [payment_intent_id, accepted, execution_request]
      properties:
        payment_intent_id:
          type: string
        accepted:
          type: boolean
        execution_request:
          $ref: "#/components/schemas/ExecutionRequest"

    ExecutionRequest:
      type: object
      required: [execution_request_id, execution_kind, aggregate_type, aggregate_id, status]
      properties:
        execution_request_id:
          type: string
        execution_kind:
          type: string
        aggregate_type:
          type: string
        aggregate_id:
          type: string
        status:
          type: string
          enum: [pending, started, completed, failed, cancelled]
        external_execution_id:
          type: string
        external_run_id:
          type: string
        last_error:
          type: string
        operation:
          type: string
          enum: [start, signal]
        signal_name:
          type: string
        dedupe_key:
          type: string
        available_at:
          type: string
          format: date-time
        dispatch_attempts:
          type: integer
          minimum: 0

    DomainEvent:
      type: object
      required: [event_type, aggregate_type, aggregate_id, sequence, visibility, payload, occurred_at]
      properties:
        event_type:
          type: string
        aggregate_type:
          type: string
        aggregate_id:
          type: string
        sequence:
          type: integer
          format: int64
        visibility:
          type: string
          enum: [public, checkout_display, order_scoped, account, admin]
        payload:
          type: object
          additionalProperties: true
        occurred_at:
          type: string
          format: date-time

    ErrorResponse:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string
