openapi: 3.1.0
info:
  title: ResearchPricer Agent API
  version: 0.2.0
  summary: Live discovery and research-brief validation for machine buyers
  description: |
    The live public ResearchPricer API lets software and AI agents discover primary-research
    capabilities and validate a structured brief. These operations are read-only and create no
    commercial commitment.

    A public read-only MCP endpoint exposes the equivalent `search_research_capabilities` and
    `validate_research_brief` tools at https://researchpricer.vercel.app/api/mcp. Firm estimates,
    quotes, orders, payments, project status and other commercial tools require managed
    organisational onboarding. Public calls to commercial REST paths return HTTP 501 with the
    machine-readable status organisation_setup_required. Onboarded organisations define agent
    identity, permitted research, budgets, approvals and payment terms before commercial access.
  contact:
    name: ResearchPricer by Stratega Market Research
    email: info@researchpricer.com
    url: https://researchpricer.com/developers
  termsOfService: https://researchpricer.com/terms
servers:
  - url: https://researchpricer.com/api/v1
    description: Production
tags:
  - name: discovery
    description: Public, non-commercial capability discovery
  - name: briefs
    description: Stateless brief validation with no commercial effect
paths:
  /:
    get:
      operationId: getApiStatus
      tags: [discovery]
      summary: Read API status and canonical discovery links
      responses:
        "200":
          description: Current public API surface
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiStatus"
  /capabilities:
    get:
      operationId: searchCapabilities
      tags: [discovery]
      summary: Discover methods, audiences, coverage and live machine actions
      responses:
        "200":
          description: ResearchPricer capability catalogue
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CapabilityCatalog"
  /briefs/validate:
    post:
      operationId: validateBrief
      tags: [briefs]
      summary: Normalise a research brief and identify missing or contradictory fields
      description: This operation is stateless. It does not save the brief, create a quote or commit funds.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ResearchBriefDraft"
            examples:
              cardiologistsSpain:
                summary: Consumer health example
                value:
                  purpose: Understand prescribing barriers for a new anticoagulant
                  markets: [ES]
                  audience:
                    type: physician
                    specialty: cardiology
                    screening:
                      - Treats at least 20 atrial-fibrillation patients per month
                  method: cawi
                  n: 200
                  loi_minutes: 15
                  deliverables: [csv, codebook, provenance]
                  currency: EUR
      responses:
        "200":
          description: The brief contains the minimum fields for a managed quote request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidatedBrief"
        "400":
          description: Invalid JSON
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "413":
          description: Request body exceeds 64 KiB
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "415":
          description: Content-Type is not application/json
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "422":
          description: Missing, contradictory or invalid brief fields
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidatedBrief"
components:
  schemas:
    ApiStatus:
      type: object
      additionalProperties: false
      required:
        - service
        - version
        - status
        - live_operations
        - openapi
        - capabilities
        - documentation
        - ard
        - mcp
        - commercial_transactions
      properties:
        service: { type: string }
        version: { type: string }
        status: { type: string, enum: [early_access] }
        live_operations:
          type: array
          items: { type: string, enum: [search_capabilities, validate_brief] }
        openapi: { type: string, format: uri }
        capabilities: { type: string, format: uri }
        documentation: { type: string, format: uri }
        ard: { type: string, format: uri }
        mcp:
          type: object
          additionalProperties: false
          required: [status, endpoint, tools, commercial_tools]
          properties:
            status: { type: string, enum: [public_read_only] }
            endpoint: { type: string, format: uri }
            tools:
              type: array
              items: { type: string, enum: [search_research_capabilities, validate_research_brief] }
            commercial_tools: { type: string, enum: [organisation_setup_required] }
        commercial_transactions: { type: string, enum: [managed_organisation_setup] }
    CapabilityCatalog:
      type: object
      additionalProperties: false
      required:
        - schema_version
        - service
        - status
        - proposition
        - coverage
        - audience_types
        - methods
        - deliverables
        - supported_examples
        - live_machine_actions
        - ordering
        - roadmap
      properties:
        schema_version: { type: string }
        service: { type: string, const: ResearchPricer }
        status: { type: string, enum: [early_access] }
        proposition: { type: string }
        coverage:
          type: object
          additionalProperties: false
          required: [scope, operating_base, rule]
          properties:
            scope: { type: string, enum: [worldwide] }
            operating_base: { type: string }
            rule: { type: string }
        audience_types:
          type: array
          items: { $ref: "#/components/schemas/AudienceType" }
        methods:
          type: array
          items: { $ref: "#/components/schemas/Method" }
        deliverables:
          type: array
          items: { $ref: "#/components/schemas/Deliverable" }
        supported_examples:
          type: array
          items: { type: string }
        live_machine_actions:
          type: array
          items:
            type: object
            additionalProperties: false
            required: [operation, method, path, commercial_effect]
            properties:
              operation: { type: string }
              method: { type: string, enum: [GET, POST] }
              path: { type: string }
              commercial_effect: { type: string, enum: [none] }
        ordering:
          type: object
          additionalProperties: false
          required: [current_mode, request_url, contact_email, commitment_rule]
          properties:
            current_mode: { type: string, enum: [managed_organisation_setup] }
            request_url: { type: string }
            contact_email: { type: string, format: email }
            commitment_rule: { type: string }
        roadmap:
          type: object
          additionalProperties: false
          required: [estimate_quote_order_api, mcp_server, a2a_endpoint, autonomous_checkout]
          properties:
            estimate_quote_order_api: { type: string }
            mcp_server: { type: string }
            a2a_endpoint: { type: string }
            autonomous_checkout: { type: string }
    ResearchBriefDraft:
      type: object
      additionalProperties: false
      properties:
        purpose:
          type: string
          minLength: 1
          maxLength: 2000
        markets:
          type: array
          minItems: 1
          maxItems: 50
          items:
            type: string
            pattern: "^[A-Za-z]{2}$"
            description: ISO 3166-1 alpha-2
        languages:
          type: array
          maxItems: 50
          items: { type: string, minLength: 1, maxLength: 50 }
        audience:
          type: object
          additionalProperties: false
          properties:
            type: { $ref: "#/components/schemas/AudienceType" }
            specialty: { type: string, minLength: 1, maxLength: 200 }
            segment: { type: string, minLength: 1, maxLength: 500 }
            screening:
              type: array
              maxItems: 40
              items: { type: string, minLength: 1, maxLength: 500 }
            exclusions:
              type: array
              maxItems: 40
              items: { type: string, minLength: 1, maxLength: 500 }
        method: { $ref: "#/components/schemas/Method" }
        n: { type: integer, minimum: 1, maximum: 1000000 }
        n_per_market: { type: integer, minimum: 1, maximum: 1000000 }
        loi_minutes: { type: integer, minimum: 1, maximum: 240 }
        duration_minutes: { type: integer, minimum: 1, maximum: 480 }
        deliverables:
          type: array
          minItems: 1
          maxItems: 10
          items: { $ref: "#/components/schemas/Deliverable" }
        currency:
          type: string
          pattern: "^[A-Za-z]{3}$"
          default: EUR
        priority:
          type: string
          enum: [standard, expedited]
          default: standard
        dates:
          type: object
          additionalProperties: false
          properties:
            earliest_start: { type: string, format: date }
            deadline: { type: string, format: date }
    ValidatedBrief:
      type: object
      additionalProperties: true
      required:
        - state
        - schema_version
      properties:
        state:
          type: string
          enum: [ready_for_quote_request, needs_clarification]
        schema_version: { type: string }
        lane: { type: string, enum: [green, amber, red] }
        brief_hash: { type: string, pattern: "^[a-f0-9]{64}$" }
        canonical_brief: { $ref: "#/components/schemas/ResearchBriefDraft" }
        missing_fields:
          type: array
          items: { type: string }
        contradictions:
          type: array
          items: { type: string }
        issues:
          type: array
          items:
            type: object
            additionalProperties: false
            required: [path, code, message]
            properties:
              path: { type: string }
              code: { type: string }
              message: { type: string }
        commercial_effect: { type: string, enum: [none] }
        next:
          type: object
          additionalProperties: true
    Error:
      type: object
      additionalProperties: true
      required: [error]
      properties:
        error: { type: string }
        message: { type: string }
        max_bytes: { type: integer }
    Method:
      type: string
      enum:
        - cawi
        - cati
        - capi
        - idi
        - focus_group
        - online_focus_group
        - online_community
        - ethnography
        - ux
        - expert_interview
        - mystery_shopping
        - clt
        - product_test
        - taste_test
        - in_home
        - recruitment_only
    AudienceType:
      type: string
      enum: [consumer, customer, b2b, executive, physician, hcp, patient, caregiver, payer, expert, rare]
    Deliverable:
      type: string
      enum: [csv, xlsx, sav, json, codebook, tables, transcripts, recordings, summary, provenance]
