openapi: 3.1.0
jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
info:
  title: ChainMandate Public Agent Surface API
  version: 1.0.0
  description: |
    Public, side-effect-free discovery, buyer qualification and decision-demo
    endpoints for ChainMandate.

    This contract does not expose the SigFence policy engine, issue production
    receipts, provision API keys, create contracts, move funds or charge wallets.
    The separate `/sigfence-openapi.yaml` document is a reference contract for
    customer or pilot deployments and is not callable on this origin.
servers:
  - url: /
    description: Same origin as this document
tags:
  - name: Discovery
  - name: Qualification
  - name: Demonstration
  - name: Network reference
  - name: Operators

paths:
  /.well-known/chainmandate.json:
    get:
      tags: [Discovery]
      operationId: getChainMandateManifest
      summary: Read the static ChainMandate service manifest
      security: []
      responses:
        '200':
          description: Machine-readable capabilities, boundaries and public endpoints.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceCatalog'

  /api/catalog:
    get:
      tags: [Discovery]
      operationId: getChainMandateCatalog
      summary: Read the origin-aware ChainMandate service catalog
      security: []
      responses:
        '200':
          description: Catalog with absolute same-origin endpoint URLs.
          headers:
            Access-Control-Allow-Origin:
              schema:
                type: string
                const: '*'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ServiceCatalog'

  /api/buyers/schema:
    get:
      tags: [Qualification]
      operationId: getBuyerRequestSchema
      summary: Read the JSON Schema for buyer qualification requests
      security: []
      responses:
        '200':
          description: JSON Schema draft 2020-12 document.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonSchemaDocument'

  /api/buyers/qualify:
    options:
      tags: [Qualification]
      operationId: optionsBuyerQualification
      summary: Discover browser CORS support for buyer qualification
      security: []
      responses:
        '204':
          description: POST with application/json is allowed.
    post:
      tags: [Qualification]
      operationId: qualifyBuyer
      summary: Qualify an agent buyer without creating commercial side effects
      description: |
        Returns a deterministic recommendation. A `QUALIFIED` decision is not an
        offer, contract, entitlement, production approval or payment authorization.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuyerRequest'
      responses:
        '200':
          description: Deterministic, side-effect-free qualification result.
          headers:
            X-ChainMandate-Boundary:
              schema:
                type: string
                const: qualification-only
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuyerQualification'
        '400':
          description: Invalid JSON or request that does not match the closed schema.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: Request body exceeds 65,536 bytes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '415':
          description: Content-Type is not application/json.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/demo/evaluate:
    options:
      tags: [Demonstration]
      operationId: optionsDecisionDemo
      summary: Discover browser CORS support for the public demo
      security: []
      responses:
        '204':
          description: POST with application/json is allowed.
    post:
      tags: [Demonstration]
      operationId: evaluateDemoIntent
      summary: Demonstrate ALLOW, DENY and REVIEW response semantics
      description: |
        This endpoint is unsigned and has no production authority. It never
        receives a wallet, private key, transaction, live position or real approval.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DemoRequest'
      responses:
        '200':
          description: Unsigned response-contract demonstration.
          headers:
            X-ChainMandate-Boundary:
              schema:
                type: string
                const: demo-only
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DemoResponse'
        '400':
          description: Invalid JSON or closed-schema mismatch.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DemoErrorResponse'
        '413':
          description: Request body exceeds 8,192 bytes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DemoErrorResponse'
        '415':
          description: Content-Type is not application/json.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DemoErrorResponse'

  /api/network/catalog:
    get:
      tags: [Network reference]
      operationId: getNetworkReferenceCatalog
      summary: Read the public, non-live network reference catalog
      description: Returns explicit non-live status, token and x402 boundaries, job lifecycle, operator roles and reference economics.
      security: []
      responses:
        '200':
          description: Side-effect-free network reference catalog. No deployed testnet or live economic activity is claimed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NetworkCatalog'

  /api/network/simulate:
    options:
      tags: [Network reference]
      operationId: optionsNetworkSimulation
      summary: Discover browser CORS support for reference simulation
      security: []
      responses:
        '204':
          description: POST with application/json is allowed.
    post:
      tags: [Network reference]
      operationId: simulateNetworkJob
      summary: Simulate committee, commit/reveal, quorum and fee allocation
      description: |
        Deterministic and side-effect-free. The response is not onchain, is not
        persisted, moves no funds, settles nothing and has no production authority.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NetworkSimulationRequest'
      responses:
        '200':
          description: Local reference trace and exact micro-USDC accounting calculation.
          headers:
            X-ChainMandate-Boundary:
              schema:
                type: string
                const: public-reference-simulation-only
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/NetworkSimulationResponse'
        '400':
          description: Invalid JSON, closed-schema mismatch or inconsistent committee counts.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulationErrorResponse'
        '413':
          description: Request body exceeds 8,192 bytes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulationErrorResponse'
        '415':
          description: Content-Type is not application/json.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulationErrorResponse'

  /api/operators/schema:
    get:
      tags: [Operators]
      operationId: getOperatorApplicationSchema
      summary: Read the closed operator application JSON Schema
      description: The browser generator downloads files locally; this API does not accept, submit, verify, approve or persist applications.
      security: []
      responses:
        '200':
          description: JSON Schema draft 2020-12 document.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JsonSchemaDocument'

components:
  schemas:
    ServiceCatalog:
      type: object
      additionalProperties: false
      required:
        - schema
        - schema_version
        - name
        - engine
        - description
        - updated_at
        - audience
        - mode
        - decisions
        - capabilities
        - hard_boundaries
        - endpoints
        - buyer_qualification
        - protocol_compatibility
        - network_reference
        - reference_contracts
        - commercial_access
      properties:
        schema:
          type: string
          format: uri
        schema_version:
          type: string
          const: 1.0.0
        name:
          type: string
          const: ChainMandate
        engine:
          type: string
          const: SigFence
        description:
          type: string
        updated_at:
          type: string
          format: date-time
        audience:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum: [ai_agent, agent_platform, smart_wallet, treasury_automation]
        mode:
          type: string
          const: advisory_shadow
        decisions:
          type: array
          minItems: 3
          maxItems: 3
          uniqueItems: true
          items:
            type: string
            enum: [ALLOW, DENY, REVIEW]
        capabilities:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
        hard_boundaries:
          $ref: '#/components/schemas/HardBoundaries'
        endpoints:
          $ref: '#/components/schemas/PublicEndpoints'
        buyer_qualification:
          $ref: '#/components/schemas/BuyerQualificationBoundary'
        demonstration:
          $ref: '#/components/schemas/DemonstrationBoundary'
        protocol_compatibility:
          $ref: '#/components/schemas/ProtocolCompatibility'
        network_reference:
          $ref: '#/components/schemas/NetworkReference'
        reference_contracts:
          $ref: '#/components/schemas/ReferenceContracts'
        commercial_access:
          $ref: '#/components/schemas/CommercialAccess'

    HardBoundaries:
      type: object
      additionalProperties: false
      required:
        - custody
        - key_access
        - signing
        - order_routing
        - execution
        - investment_selection
        - free_form_prompt_execution
      properties:
        custody: { type: boolean, const: false }
        key_access: { type: boolean, const: false }
        signing: { type: boolean, const: false }
        order_routing: { type: boolean, const: false }
        execution: { type: boolean, const: false }
        investment_selection: { type: boolean, const: false }
        free_form_prompt_execution: { type: boolean, const: false }

    PublicEndpoints:
      type: object
      additionalProperties: false
      required:
        - catalog
        - manifest
        - demonstration
        - buyer_qualification
        - buyer_request_schema
        - network_catalog
        - network_simulation
        - operator_application_schema
        - site_openapi
      properties:
        catalog: { type: string, format: uri-reference }
        manifest: { type: string, format: uri-reference }
        demonstration: { type: string, format: uri-reference }
        buyer_qualification: { type: string, format: uri-reference }
        buyer_request_schema: { type: string, format: uri-reference }
        network_catalog: { type: string, format: uri-reference }
        network_simulation: { type: string, format: uri-reference }
        operator_application_schema: { type: string, format: uri-reference }
        site_openapi: { type: string, format: uri-reference }

    BuyerQualificationBoundary:
      type: object
      additionalProperties: false
      required:
        - method
        - side_effects
        - decisions
        - creates_contract
        - provisions_api_key
        - moves_funds
      properties:
        method: { type: string, const: POST }
        side_effects: { type: boolean, const: false }
        decisions:
          type: array
          minItems: 3
          maxItems: 3
          uniqueItems: true
          items:
            type: string
            enum: [QUALIFIED, REVIEW, NOT_SUPPORTED]
        creates_contract: { type: boolean, const: false }
        provisions_api_key: { type: boolean, const: false }
        moves_funds: { type: boolean, const: false }

    DemonstrationBoundary:
      type: object
      additionalProperties: false
      required: [method, content_type, signed_receipt, production_authority, input]
      properties:
        method: { type: string, const: POST }
        content_type: { type: string, const: application/json }
        signed_receipt: { type: boolean, const: false }
        production_authority: { type: boolean, const: false }
        input:
          type: object
          additionalProperties:
            type: string

    ProtocolCompatibility:
      type: object
      additionalProperties: false
      required: [a2a, mcp, x402, note]
      properties:
        a2a: { type: string, const: not_implemented }
        mcp: { type: string, const: separate_adapter_implemented_not_publicly_deployed }
        x402: { type: string, const: core_api_implemented_not_configured }
        note:
          type: string

    NetworkReference:
      type: object
      additionalProperties: false
      required: [status, network_live, public_testnet_deployed, operator_count_reported, users_reported, revenue_reported, x402, token, funds_movement, settlement, note]
      properties:
        status: { type: string, const: public_reference_only }
        network_live: { type: boolean, const: false }
        public_testnet_deployed: { type: boolean, const: false }
        operator_count_reported: { type: 'null' }
        users_reported: { type: 'null' }
        revenue_reported: { type: 'null' }
        x402: { type: string, const: not_used_by_network_simulator }
        token: { type: string, const: not_issued }
        funds_movement: { type: boolean, const: false }
        settlement: { type: boolean, const: false }
        note: { type: string }

    NetworkCatalog:
      type: object
      additionalProperties: false
      required: [schema_version, name, status, description, network_live, public_testnet_deployed, chain_id, users_reported, revenue_reported, token, operator_model, job_lifecycle, reference_economics, endpoints, boundaries]
      properties:
        schema_version: { type: string, const: chainmandate.network-catalog/v1 }
        name: { type: string, const: ChainMandate Network }
        status: { type: string, const: public_reference_only }
        description: { type: string }
        network_live: { type: boolean, const: false }
        public_testnet_deployed: { type: boolean, const: false }
        chain_id: { type: 'null' }
        users_reported: { type: 'null' }
        revenue_reported: { type: 'null' }
        token:
          type: object
          additionalProperties: false
          required: [status, symbol, contract_address, sale_active, mining_rewards_active, staking_active]
          properties:
            status: { type: string, const: not_issued }
            symbol: { type: 'null' }
            contract_address: { type: 'null' }
            sale_active: { type: boolean, const: false }
            mining_rewards_active: { type: boolean, const: false }
            staking_active: { type: boolean, const: false }
        operator_model:
          type: object
          additionalProperties: false
          required: [roles, registered_operator_count, committee_sizes, quorum_rule, selection]
          properties:
            roles:
              type: array
              prefixItems:
                - { type: string, const: prover }
                - { type: string, const: validator }
                - { type: string, const: watcher }
              minItems: 3
              maxItems: 3
            registered_operator_count: { type: 'null' }
            committee_sizes:
              type: array
              prefixItems:
                - { type: integer, const: 3 }
                - { type: integer, const: 5 }
                - { type: integer, const: 7 }
              minItems: 3
              maxItems: 3
            quorum_rule: { type: string, const: 'ceil(2n/3) matching reveals' }
            selection: { type: string }
        job_lifecycle:
          type: array
          prefixItems:
            - { type: string, const: JOB }
            - { type: string, const: COMMITTEE }
            - { type: string, const: COMMIT }
            - { type: string, const: REVEAL }
            - { type: string, const: QUORUM }
            - { type: string, const: FEE_SPLIT }
          minItems: 6
          maxItems: 6
        reference_economics:
          type: object
          additionalProperties: false
          required: [denomination, illustrative_only, protocol_percent, policy_author_percent, prover_percent, validator_pool_percent, operations_percent, reserve_percent, validator_eligibility, integer_rounding, no_quorum_behavior, x402]
          properties:
            denomination: { type: string, const: micro-USDC }
            illustrative_only: { type: boolean, const: true }
            protocol_percent: { type: integer, const: 20 }
            policy_author_percent: { type: integer, const: 5 }
            prover_percent: { type: integer, const: 25 }
            validator_pool_percent: { type: integer, const: 30 }
            operations_percent: { type: integer, const: 10 }
            reserve_percent: { type: integer, const: 10 }
            validator_eligibility: { type: string, const: 'revealed validator committee members only; prover excluded' }
            integer_rounding: { type: string, const: all percentage and validator-distribution remainders are added to reserve }
            no_quorum_behavior: { type: string }
            x402: { type: string, const: not_implemented }
        endpoints:
          type: object
          additionalProperties: false
          required: [catalog, simulation, operator_schema, explorer, operator_application, control]
          properties:
            catalog: { type: string, format: uri }
            simulation: { type: string, format: uri }
            operator_schema: { type: string, format: uri }
            explorer: { type: string, format: uri }
            operator_application: { type: string, format: uri }
            control: { type: string, format: uri }
        boundaries:
          type: object
          additionalProperties: false
          required: [side_effects, persistence, funds_movement, settlement, production_authority]
          properties:
            side_effects: { type: boolean, const: false }
            persistence: { type: boolean, const: false }
            funds_movement: { type: boolean, const: false }
            settlement: { type: boolean, const: false }
            production_authority: { type: boolean, const: false }

    NetworkSimulationRequest:
      type: object
      additionalProperties: false
      required: [schema_version, job_type, job_fee_microusdc, committee_size, commits, reveals]
      properties:
        schema_version: { type: string, const: chainmandate.network-simulation/v1 }
        job_type: { type: string, enum: [policy_evaluation, receipt_verification, compliance_check] }
        job_fee_microusdc: { type: string, pattern: '^[1-9][0-9]{0,11}$' }
        committee_size: { type: integer, enum: [3, 5, 7] }
        commits: { type: integer, minimum: 0, maximum: 7 }
        reveals: { type: integer, minimum: 0, maximum: 7 }

    NetworkSimulationResponse:
      type: object
      additionalProperties: false
      required: [schema_version, simulation_id, mode, input, quorum, committee, phases, fee_split_microusdc, boundaries]
      properties:
        schema_version: { type: string, const: chainmandate.network-simulation-result/v1 }
        simulation_id: { type: string }
        mode: { type: string, const: public_reference_simulation }
        input: { $ref: '#/components/schemas/NetworkSimulationRequest' }
        quorum:
          type: object
          additionalProperties: false
          required: [rule, threshold, commits_received, reveals_received, reached]
          properties:
            rule: { type: string, const: 'ceil(2n/3)' }
            threshold: { type: integer, minimum: 2, maximum: 5 }
            commits_received: { type: integer, minimum: 0, maximum: 7 }
            reveals_received: { type: integer, minimum: 0, maximum: 7 }
            reached: { type: boolean }
        committee:
          type: array
          minItems: 3
          maxItems: 7
          items:
            type: object
            additionalProperties: false
            required: [operator_id, commit_status, reveal_status, identity_status, validator_reward_microusdc]
            properties:
              operator_id: { type: string, pattern: '^reference-op-[0-9]{2}$' }
              commit_status: { type: string, enum: [COMMITTED, MISSING] }
              reveal_status: { type: string, enum: [REVEALED, MISSING] }
              identity_status: { type: string, const: SYNTHETIC }
              validator_reward_microusdc: { type: string, pattern: '^[0-9]+$' }
        phases:
          type: array
          minItems: 6
          maxItems: 6
          items:
            type: object
            additionalProperties: false
            required: [phase, status]
            properties:
              phase: { type: string, enum: [JOB, COMMITTEE, COMMIT, REVEAL, QUORUM, FEE_SPLIT] }
              status: { type: string }
        fee_split_microusdc:
          type: object
          additionalProperties: false
          required: [total, protocol, policy_author, prover, validator_pool_target, validator_pool_distributed, per_revealing_validator, operations, base_reserve, percentage_rounding_to_reserve, validator_rounding_to_reserve, rounding_to_reserve, reserve, reference_refund]
          properties:
            total: { type: string, pattern: '^[0-9]+$' }
            protocol: { type: string, pattern: '^[0-9]+$' }
            policy_author: { type: string, pattern: '^[0-9]+$' }
            prover: { type: string, pattern: '^[0-9]+$' }
            validator_pool_target: { type: string, pattern: '^[0-9]+$' }
            validator_pool_distributed: { type: string, pattern: '^[0-9]+$' }
            per_revealing_validator: { type: string, pattern: '^[0-9]+$' }
            operations: { type: string, pattern: '^[0-9]+$' }
            base_reserve: { type: string, pattern: '^[0-9]+$' }
            percentage_rounding_to_reserve: { type: string, pattern: '^[0-9]+$' }
            validator_rounding_to_reserve: { type: string, pattern: '^[0-9]+$' }
            rounding_to_reserve: { type: string, pattern: '^[0-9]+$' }
            reserve: { type: string, pattern: '^[0-9]+$' }
            reference_refund: { type: string, pattern: '^[0-9]+$' }
        boundaries:
          type: object
          additionalProperties: false
          required: [side_effects, persisted, onchain, settlement_executed, signed_receipt, production_authority, x402, token]
          properties:
            side_effects: { type: boolean, const: false }
            persisted: { type: boolean, const: false }
            onchain: { type: boolean, const: false }
            settlement_executed: { type: boolean, const: false }
            signed_receipt: { type: boolean, const: false }
            production_authority: { type: boolean, const: false }
            x402: { type: string, const: not_implemented }
            token: { type: string, const: not_issued }

    ReferenceContracts:
      type: object
      additionalProperties: false
      required:
        - public_site_openapi
        - sigfence_core_openapi
        - sigfence_core_callable_on_this_origin
      properties:
        public_site_openapi: { type: string, format: uri-reference }
        sigfence_core_openapi: { type: string, format: uri-reference }
        sigfence_core_callable_on_this_origin: { type: boolean, const: false }

    CommercialAccess:
      type: object
      additionalProperties: false
      required:
        - status
        - discovery_price
        - builder
        - production
        - enterprise
        - safety_sprint
        - billing_basis
        - planned_payg_usdc
        - x402
        - autonomous_wallet_charge
        - creates_contract
        - allow_semantics
        - contact
      properties:
        status: { type: string, const: planned_pilot_not_contracting }
        discovery_price: { type: string, const: 0 EUR }
        builder: { type: string, const: 249 EUR/month }
        production: { type: string, const: 1490 EUR/month }
        enterprise: { type: string, const: 7500+ EUR/month }
        safety_sprint: { type: string, const: 7500 EUR one-time }
        billing_basis: { type: string }
        planned_payg_usdc:
          type: object
          additionalProperties: false
          required: [receipt_revalidate, policy_evaluate, transaction_simulate, quorum_policy_evaluate, quorum_transaction_simulate]
          properties:
            receipt_revalidate: { type: string, const: "0.01" }
            policy_evaluate: { type: string, const: "0.05" }
            transaction_simulate: { type: string, const: "0.15" }
            quorum_policy_evaluate: { type: string, const: "0.25" }
            quorum_transaction_simulate: { type: string, const: "0.75" }
        x402: { type: string, const: core_api_implemented_not_configured }
        autonomous_wallet_charge: { type: boolean, const: false }
        creates_contract: { type: boolean, const: false }
        allow_semantics: { type: string, const: policy_match_only_not_advice_or_execution_authority }
        contact: { type: string, format: uri }

    JsonSchemaDocument:
      type: object
      required: [$schema, $id, type, additionalProperties, required, properties]
      properties:
        $schema: { type: string, format: uri }
        $id: { type: string, format: uri }
        title: { type: string }
        type: { type: string, const: object }
        additionalProperties: { type: boolean, const: false }
        required:
          type: array
          items: { type: string }
        properties: { type: object }

    BuyerRequest:
      type: object
      additionalProperties: false
      required:
        - schema_version
        - buyer_id
        - buyer_type
        - organization
        - use_case
        - deployment_stage
        - agent_count
        - evaluations_per_month
        - deployment_preference
        - instrument_types
        - order_types
        - needs_private_keys
        - needs_signing
        - needs_execution
        - needs_custody
        - needs_strategy
        - needs_funds_movement
        - requires_enforcement
        - connector_available
        - purchase_authority
        - budget_eur_monthly
        - start_window_days
      properties:
        schema_version:
          type: string
          const: chainmandate.buyer-request/v1
        buyer_id:
          type: string
          pattern: '^[A-Za-z0-9][A-Za-z0-9_.:-]{2,127}$'
        buyer_type:
          type: string
          enum: [autonomous_agent, agent_platform, human_sponsored_agent]
        organization:
          type: string
          minLength: 1
          maxLength: 160
          pattern: '\S'
        use_case:
          type: string
          enum: [agent_wallet, smart_account, trading_agent, treasury_agent, agent_platform, security_infrastructure]
        deployment_stage:
          type: string
          enum: [idea, prototype, pilot, production]
        agent_count: { type: integer, minimum: 1, maximum: 1000000 }
        evaluations_per_month: { type: integer, minimum: 1, maximum: 1000000000 }
        deployment_preference:
          type: string
          enum: [shared, dedicated, self_hosted]
        instrument_types:
          type: array
          minItems: 1
          maxItems: 32
          uniqueItems: true
          items: { type: string, pattern: '^[a-z][a-z0-9_-]{0,31}$' }
        order_types:
          type: array
          minItems: 1
          maxItems: 32
          uniqueItems: true
          items: { type: string, pattern: '^[a-z][a-z0-9_-]{0,31}$' }
        needs_private_keys: { type: boolean }
        needs_signing: { type: boolean }
        needs_execution: { type: boolean }
        needs_custody: { type: boolean }
        needs_strategy: { type: boolean }
        needs_funds_movement: { type: boolean }
        requires_enforcement: { type: boolean }
        connector_available: { type: boolean }
        purchase_authority: { type: boolean }
        budget_eur_monthly: { type: integer, minimum: 0, maximum: 1000000000 }
        start_window_days: { type: integer, minimum: 0, maximum: 3650 }

    BuyerQualification:
      type: object
      additionalProperties: false
      required:
        - schema_version
        - qualification_id
        - request_sha256
        - buyer_id
        - decision
        - score
        - score_components
        - hard_boundary_mismatches
        - review_reasons
        - recommended_offer
        - recommended_subscription
        - monthly_list_price_eur
        - autonomous_purchase_available
        - x402_enabled
        - api_key_status
        - next_action
        - receipt_flow
        - claims
      properties:
        schema_version: { type: string, const: chainmandate.buyer-qualification/v1 }
        qualification_id: { type: string, pattern: '^qual_[a-f0-9]{24}$' }
        request_sha256: { type: string, pattern: '^[a-f0-9]{64}$' }
        buyer_id: { type: string }
        decision: { type: string, enum: [QUALIFIED, REVIEW, NOT_SUPPORTED] }
        score: { type: integer, minimum: 0, maximum: 100 }
        score_components:
          type: object
          additionalProperties: false
          required: [use_case_fit, deployment_stage, risk_volume, multi_agent_need, connector_readiness, purchase_authority, start_timing]
          properties:
            use_case_fit: { type: integer }
            deployment_stage: { type: integer }
            risk_volume: { type: integer }
            multi_agent_need: { type: integer }
            connector_readiness: { type: integer }
            purchase_authority: { type: integer }
            start_timing: { type: integer }
        hard_boundary_mismatches:
          type: array
          items: { type: string }
        review_reasons:
          type: array
          items: { type: string }
        recommended_offer:
          type: string
          enum: [builder, production, enterprise, agent_safety_sprint]
        recommended_subscription:
          type: string
          enum: [builder, production, enterprise]
        monthly_list_price_eur: { type: integer, enum: [249, 1490, 7500] }
        autonomous_purchase_available: { type: boolean, const: false }
        x402_enabled: { type: boolean, const: false }
        api_key_status: { type: string, const: not_provisioned }
        next_action:
          type: string
          enum: [stop_boundary_mismatch, human_scope_contract_and_payment_gate, resolve_review_reasons]
        receipt_flow:
          type: object
          additionalProperties: false
          required: [decision_endpoint, verification_endpoint, audit_endpoint, receipt_usable_only_for_allow, advisory_only]
          properties:
            decision_endpoint: { type: string, const: /v1/evaluations }
            verification_endpoint: { type: string, const: /v1/receipts/verify }
            audit_endpoint: { type: string, const: /v1/audit/verify }
            receipt_usable_only_for_allow: { type: boolean, const: true }
            advisory_only: { type: boolean, const: true }
        claims:
          type: object
          additionalProperties: false
          required: [advisory_only, signs_or_executes, qualification_is_not_an_offer_or_contract]
          properties:
            advisory_only: { type: boolean, const: true }
            signs_or_executes: { type: boolean, const: false }
            qualification_is_not_an_offer_or_contract: { type: boolean, const: true }

    DemoRequest:
      type: object
      additionalProperties: false
      required: [notional_usd, leverage, current_exposure_usd, verified_state]
      properties:
        notional_usd: { $ref: '#/components/schemas/UnsignedIntegerString' }
        leverage: { $ref: '#/components/schemas/UnsignedIntegerString' }
        current_exposure_usd: { $ref: '#/components/schemas/UnsignedIntegerString' }
        verified_state: { type: boolean }

    UnsignedIntegerString:
      type: string
      pattern: '^(0|[1-9][0-9]{0,8})$'

    DemoResponse:
      type: object
      additionalProperties: false
      required:
        - schema_version
        - decision
        - findings
        - mandate
        - signed_receipt
        - currently_usable
        - demonstration_only
        - warning
      properties:
        schema_version: { type: string, const: demo-1 }
        decision: { type: string, enum: [ALLOW, DENY, REVIEW] }
        findings:
          type: array
          minItems: 1
          items:
            type: object
            additionalProperties: false
            required: [code, message]
            properties:
              code: { type: string }
              message: { type: string }
        mandate:
          type: object
          additionalProperties: false
          required: [max_order_notional_usd, max_leverage, max_total_exposure_usd]
          properties:
            max_order_notional_usd: { type: string, const: '500' }
            max_leverage: { type: string, const: '3' }
            max_total_exposure_usd: { type: string, const: '1000' }
        signed_receipt: { type: 'null' }
        currently_usable: { type: boolean, const: false }
        demonstration_only: { type: boolean, const: true }
        warning: { type: string }

    ErrorResponse:
      type: object
      additionalProperties: false
      required: [error]
      properties:
        error: { type: string }

    DemoErrorResponse:
      type: object
      additionalProperties: false
      required: [error, demonstration_only]
      properties:
        error: { type: string }
        demonstration_only: { type: boolean, const: true }

    SimulationErrorResponse:
      type: object
      additionalProperties: false
      required: [error, simulation_only]
      properties:
        error: { type: string }
        simulation_only: { type: boolean, const: true }
