arazzo: 1.0.1
info:
  title: Exayard Workflows
  version: 1.0.0
  summary: >
    Machine-readable workflows that describe common multi-step operations
    over the Exayard /v1 API. Agents use these to plan tool sequences
    before dispatching individual calls — without this, each agent
    re-derives the happy path. Mirrors what the MCP prompts primitive
    does for interactive agents, but in OpenAPI-native form for
    schema-driven code generators.
  description: |
    See https://api.exayard.com/v1/openapi.json for the individual operation
    definitions. These workflows compose those operations.
sourceDescriptions:
  - name: exayard-v1
    url: https://api.exayard.com/v1/openapi.json
    type: openapi

workflows:
  - workflowId: run-takeoff-end-to-end
    summary: Upload a plan, run an AI assessment, review proposed elements, and approve them.
    description: >
      The canonical ingest flow. Starts from an existing project; ends with
      approved symbols bound to the canvas. Pause between steps 3 and 4 for
      user confirmation — approved elements drive downstream pricing.
    inputs:
      type: object
      required: [organizationId, projectId]
      properties:
        organizationId: { type: string }
        projectId: { type: string }
    steps:
      - stepId: list-pages
        description: Confirm the project has indexed pages to run the assessment on.
        operationId: listPages
        parameters:
          - { name: projectId, in: query, value: $inputs.projectId }
        successCriteria:
          - condition: $statusCode == 200
      - stepId: start-assessment
        description: Kick off the AI assessment over the project's pages.
        operationId: createAssessment
        parameters:
          - { name: projectId, in: path, value: $inputs.projectId }
        requestBody:
          contentType: application/json
          payload:
            organizationId: $inputs.organizationId
        successCriteria:
          - condition: $statusCode == 200
        outputs:
          assessmentId: $response.body#/_id
      - stepId: poll-assessment
        description: Poll until the assessment reaches `awaiting_approval`.
        operationId: getAssessment
        parameters:
          - { name: id, in: path, value: $steps.start-assessment.outputs.assessmentId }
          - { name: organizationId, in: query, value: $inputs.organizationId }
        successCriteria:
          - condition: $response.body#/status == "awaiting_approval"
            type: simple
      - stepId: user-review
        description: Halt for user confirmation of the detected elements before approving.
        x-arazzo-human-in-the-loop: true
      - stepId: approve-assessment
        description: Approve the reviewed elements, turning them into canvas symbols.
        operationId: approveAssessment
        parameters:
          - { name: id, in: path, value: $steps.start-assessment.outputs.assessmentId }
        requestBody:
          contentType: application/json
          payload:
            organizationId: $inputs.organizationId
            approvedElements: '{user-supplied subset of detectedElements}'
    outputs:
      assessmentId: $steps.start-assessment.outputs.assessmentId

  - workflowId: generate-bid-from-takeoff
    summary: Turn an approved takeoff into a priced bid document.
    description: >
      Runs after a successful `run-takeoff-end-to-end`. Validates pricing
      before producing the bid so agents never publish fabricated numbers.
    inputs:
      type: object
      required: [organizationId, projectId]
      properties:
        organizationId: { type: string }
        projectId: { type: string }
    steps:
      - stepId: list-symbols
        description: Enumerate the bound symbols on the canvas.
        operationId: listSymbols
        parameters:
          - { name: projectId, in: query, value: $inputs.projectId }
          - { name: organizationId, in: query, value: $inputs.organizationId }
      - stepId: validate-pricing
        description: >
          For each line item, confirm vendor pricing is current via
          get_best_price_for_product. Stop the workflow if any product
          is missing a price — never fabricate.
        x-arazzo-loop: true
      - stepId: create-bid
        description: Generate the bid document (blocking 30–60s).
        operationId: createBid
        parameters:
          - { name: id, in: path, value: $inputs.projectId }
        requestBody:
          contentType: application/json
          payload:
            organizationId: $inputs.organizationId
            measurementContext: '{totals-by-symbol summary}'
    outputs:
      bidDocumentId: $steps.create-bid.outputs.documentId

  - workflowId: subscribe-to-lifecycle
    summary: Register a webhook endpoint for project lifecycle events.
    inputs:
      type: object
      required: [organizationId, url, events]
      properties:
        organizationId: { type: string }
        url: { type: string, format: uri }
        events: { type: array, items: { type: string } }
    steps:
      - stepId: create-endpoint
        description: Create the endpoint and capture the one-shot signing secret.
        operationId: createWebhookEndpoint
        requestBody:
          contentType: application/json
          payload:
            organizationId: $inputs.organizationId
            url: $inputs.url
            events: $inputs.events
        outputs:
          endpointId: $response.body#/id
          secret: $response.body#/secret
      - stepId: store-secret
        description: >
          Persist the secret in the caller's own key store. The endpoint
          will never return it again, so a lost secret means deleting and
          recreating the endpoint.
        x-arazzo-human-in-the-loop: true
    outputs:
      endpointId: $steps.create-endpoint.outputs.endpointId
      secret: $steps.create-endpoint.outputs.secret
