openapi: 3.1.0
info:
  title: Rover Agent-to-Web API
  version: 2.0.0
  summary: Strict v2 browser-agent execution for Rover-enabled websites.
servers:
  - url: https://agent.rtrvr.ai
security:
  - {}
  - webBotAuth: []
  - roverDelegation: []
  - accessToken: []
paths:
  /v2/a2w/runs:
    get:
      summary: Run Rover from a URL-fetch chatbot
      parameters:
        - { name: url, in: query, required: true, schema: { type: string, format: uri } }
        - { name: prompt, in: query, schema: { type: string } }
        - { name: shortcutId, in: query, schema: { type: string } }
        - { name: playbookId, in: query, schema: { type: string } }
        - { name: engagementKind, in: query, schema: { $ref: '#/components/schemas/EngagementKind' } }
        - { name: capabilityId, in: query, schema: { type: string } }
        - { name: execution, in: query, schema: { $ref: '#/components/schemas/Execution' } }
        - { name: wait, in: query, schema: { type: integer, minimum: 0, maximum: 25, default: 25 } }
        - { name: format, in: query, schema: { type: string, enum: [markdown, json], default: markdown } }
        - { name: commerceType, in: query, schema: { type: string } }
        - { name: plan, in: query, schema: { type: string } }
        - { name: actionId, in: query, schema: { type: string } }
        - { name: maxAmount, in: query, schema: { type: number, minimum: 0 } }
        - { name: currency, in: query, schema: { type: string } }
        - { name: cadence, in: query, schema: { type: string } }
        - { name: confirmationPolicy, in: query, schema: { type: string } }
      responses:
        '200':
          description: Final or in-progress run result
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
        '400': { $ref: '#/components/responses/ContractError' }
    post:
      summary: Create a structured Rover run
      parameters:
        - { name: Idempotency-Key, in: header, schema: { type: string } }
        - { name: Prefer, in: header, schema: { type: string, example: wait=25 } }
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateRun' }
      responses:
        '200':
          description: Final result within the requested wait
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
        '202':
          description: Accepted run resource
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
        '400': { $ref: '#/components/responses/ContractError' }
  /v2/a2w/runs/{runId}:
    parameters:
      - { $ref: '#/components/parameters/RunId' }
      - { $ref: '#/components/parameters/Access' }
    get:
      summary: Read or stream a run
      responses:
        '200':
          description: Current run state or event stream
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
            text/event-stream: { schema: { type: string } }
            application/x-ndjson: { schema: { type: string } }
    post:
      summary: Continue a run requiring ordinary input
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - { type: object, additionalProperties: false, required: [input], properties: { input: { type: string } } }
                - { type: object, additionalProperties: false, required: [answers], properties: { answers: { type: object, additionalProperties: { type: string } } } }
      responses:
        '200':
          description: Resumed run
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
        '400': { $ref: '#/components/responses/ContractError' }
    delete:
      summary: Cancel a run
      responses: { '200': { description: Cancelled } }
  /v2/a2w/runs/{runId}/auth-input:
    parameters:
      - { $ref: '#/components/parameters/RunId' }
      - { $ref: '#/components/parameters/Access' }
    post:
      summary: Provide one-shot sign-in continuation data
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [kind, value]
              properties:
                kind: { type: string, enum: [magic_link, otp, unknown] }
                value: { type: string }
      responses:
        '200':
          description: Resumed run
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
        '400': { $ref: '#/components/responses/ContractError' }
  /v2/a2w/runs/{runId}/artifacts:
    parameters:
      - { $ref: '#/components/parameters/RunId' }
      - { $ref: '#/components/parameters/Access' }
    get:
      summary: Open run artifacts
      responses: { '200': { description: Artifact manifest } }
  /v2/a2w/runs/{runId}/handoffs:
    parameters:
      - { $ref: '#/components/parameters/RunId' }
      - { $ref: '#/components/parameters/Access' }
    post:
      summary: Delegate to another Rover-enabled site
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateHandoff' }
      responses:
        '202':
          description: Child run created
          content:
            application/json:
              schema: { $ref: '#/components/schemas/A2WRun' }
  /v2/a2w/workflows/{workflowId}:
    parameters:
      - { name: workflowId, in: path, required: true, schema: { type: string } }
      - { $ref: '#/components/parameters/Access' }
    get:
      summary: Read a multi-run workflow
      responses: { '200': { description: Workflow state } }
  /v2/a2w/capabilities:
    get:
      summary: Discover capabilities for a Rover-enabled URL
      parameters:
        - { name: url, in: query, schema: { type: string, format: uri } }
        - { name: host, in: query, schema: { type: string } }
        - { name: siteId, in: query, schema: { type: string } }
      responses: { '200': { description: Capability summary } }
  /v2/a2w/discovery-events:
    post:
      summary: Record redacted discovery telemetry
      responses: { '202': { description: Accepted } }
components:
  securitySchemes:
    webBotAuth:
      type: apiKey
      in: header
      name: Signature
      description: RFC 9421 HTTP Message Signature verified with Rover Web Bot Auth.
    roverDelegation:
      type: http
      scheme: bearer
      bearerFormat: Rover delegation token
    accessToken:
      type: apiKey
      in: query
      name: access
      description: Opaque run- or workflow-scoped access token returned at creation.
  parameters:
    RunId: { name: runId, in: path, required: true, schema: { type: string } }
    Access: { name: access, in: query, schema: { type: string }, description: Opaque run access token. }
  schemas:
    EngagementKind: { type: string, enum: [demo, onboarding, support, task] }
    A2WRunStatus: { type: string, enum: [pending, waiting_browser, running, input_required, completed, failed, cancelled, expired] }
    A2WInputReason:
      type: string
      enum:
        - auth_required
        - sign_in_link_required
        - account_link_required
        - payment_method_required
        - payment_confirmation_required
        - action_confirmation_required
        - human_verification_required
        - browser_takeover_required
        - merchant_policy_blocked
        - risk_review_required
        - terms_acknowledgement_required
        - offer_claim_required
    Execution: { type: string, enum: [cloud, browser], default: cloud }
    ExecutionSpec:
      type: object
      additionalProperties: false
      properties:
        preference: { type: string, enum: [cloud, browser, auto] }
        mode: { type: string, enum: [cloud, browser] }
        allowedModes:
          type: array
          uniqueItems: true
          items: { type: string, enum: [cloud, browser] }
        userPresent: { type: boolean }
    AgentAttribution:
      type: object
      additionalProperties: false
      properties:
        key: { type: string }
        displayName: { type: string }
        vendor: { type: string }
        model: { type: string }
        version: { type: string }
        homepage: { type: string, format: uri }
        memoryKey: { type: string }
        clientId: { type: string }
    Identity:
      type: object
      additionalProperties: false
      properties:
        userPresent: { type: boolean }
        sessionId: { type: string }
        agentKey: { type: string }
        memoryKey: { type: string }
    Accept:
      type: object
      additionalProperties: false
      properties:
        modes:
          type: array
          uniqueItems: true
          items: { type: string, enum: [text, markdown, json, observation, artifacts] }
        primary: { type: string, enum: [text, markdown, json, observation, artifacts] }
    Policy:
      type: object
      additionalProperties: false
      properties:
        confirmation: { type: string, enum: [required, site_policy, auto] }
        crossHost: { type: string, enum: [same_host, site_policy, allow] }
        maxHops: { type: integer, minimum: 0 }
    Subject:
      type: object
      additionalProperties: false
      properties:
        emailHint: { type: string }
        subjectId: { type: string }
        externalUserIdHash: { type: string }
        merchantUserId: { type: string }
    Auth:
      type: object
      additionalProperties: false
      properties:
        mode: { type: string }
        token: { type: string, writeOnly: true }
        scopes: { type: array, items: { type: string } }
    Payment:
      type: object
      additionalProperties: false
      properties:
        maxAmount: { type: number, minimum: 0 }
        currency: { type: string }
        cadence: { type: string }
    Commerce:
      type: object
      additionalProperties: false
      properties:
        type: { type: string }
        plan: { type: string }
        actionId: { type: string }
    CreateRun:
      type: object
      additionalProperties: false
      required: [url]
      oneOf:
        - { required: [prompt] }
        - { required: [shortcutId] }
        - { required: [playbookId] }
      properties:
        url: { type: string, format: uri }
        prompt: { type: string }
        shortcutId: { type: string }
        playbookId: { type: string }
        engagementKind: { $ref: '#/components/schemas/EngagementKind' }
        capabilityId: { type: string }
        args: { type: object, additionalProperties: true }
        agent: { $ref: '#/components/schemas/AgentAttribution' }
        identity: { $ref: '#/components/schemas/Identity' }
        execution: { $ref: '#/components/schemas/ExecutionSpec' }
        accept: { $ref: '#/components/schemas/Accept' }
        policy: { $ref: '#/components/schemas/Policy' }
        subject: { $ref: '#/components/schemas/Subject' }
        auth: { $ref: '#/components/schemas/Auth' }
        payment: { $ref: '#/components/schemas/Payment' }
        commerce: { $ref: '#/components/schemas/Commerce' }
        confirmationPolicy: { type: string, enum: [require_before_charge, auto, site_policy] }
        artifacts:
          type: array
          maxItems: 16
          items: { type: string, maxLength: 64 }
    CreateHandoff:
      type: object
      additionalProperties: false
      required: [url]
      oneOf:
        - { required: [prompt] }
        - { required: [shortcutId] }
        - { required: [playbookId] }
      properties:
        url: { type: string, format: uri }
        prompt: { type: string }
        shortcutId: { type: string }
        playbookId: { type: string }
        engagementKind: { $ref: '#/components/schemas/EngagementKind' }
        capabilityId: { type: string }
        args: { type: object, additionalProperties: true }
        agent: { $ref: '#/components/schemas/AgentAttribution' }
        identity: { $ref: '#/components/schemas/Identity' }
        execution: { $ref: '#/components/schemas/ExecutionSpec' }
        accept: { $ref: '#/components/schemas/Accept' }
        policy: { $ref: '#/components/schemas/Policy' }
        contextSummary: { type: string }
        expectedOutput: { type: string }
        lastObservation: { type: object, additionalProperties: true }
    A2WInputRequest:
      type: object
      additionalProperties: false
      properties:
        questions: { type: array, items: {} }
        askUser: { type: object, additionalProperties: true }
        message: { type: string }
        reason: { $ref: '#/components/schemas/A2WInputReason' }
        links:
          type: object
          additionalProperties: false
          properties:
            confirm: { type: string, format: uri }
            open: { type: string, format: uri }
            verify: { type: string, format: uri }
        expiresAt: { type: string, format: date-time }
        commerceStandards: { type: object, additionalProperties: true }
    A2WRun:
      type: object
      additionalProperties: false
      required: [id, protocol, runId, run, status, terminalStatuses, interactiveStatuses, links, next, execution, diagnostics, identity, request]
      properties:
        id: { type: string }
        protocol: { type: string, const: a2w }
        runId: { type: string }
        workflowId: { type: string }
        run: { type: string, format: uri }
        workflow: { type: string, format: uri }
        status: { $ref: '#/components/schemas/A2WRunStatus' }
        terminalStatuses:
          type: array
          items: { $ref: '#/components/schemas/A2WRunStatus' }
        interactiveStatuses:
          type: array
          items: { $ref: '#/components/schemas/A2WRunStatus' }
        retryAfterMs: { type: integer, minimum: 0 }
        links: { type: object, additionalProperties: true }
        next: { type: object, additionalProperties: true }
        execution: { type: object, additionalProperties: true }
        diagnostics: { type: object, additionalProperties: true }
        identity: { type: object, additionalProperties: false, required: [trust], properties: { trust: { type: string, enum: [verified, anonymous] }, upgrade: { type: string } } }
        request: { type: object, additionalProperties: true }
        open: { type: string, format: uri }
        browserLink: { type: string, format: uri }
        error: {}
        result: { type: object, additionalProperties: true }
        openedTabs: { type: array, items: { type: object, additionalProperties: true } }
        handoff: { type: object, additionalProperties: true }
        input: { $ref: '#/components/schemas/A2WInputRequest' }
        authInput:
          type: object
          additionalProperties: false
          properties:
            status: { type: string, enum: [awaiting, provided, consumed] }
            kind: { type: string, enum: [magic_link, otp, unknown] }
            prompt: { type: string }
            emailMasked: { type: string }
  responses:
    ContractError:
      description: Strict v2 contract error
      content:
        application/json:
          schema:
            type: object
            additionalProperties: false
            required: [error]
            properties:
              error:
                type: object
                additionalProperties: false
                required: [code, message]
                properties:
                  code: { type: string, enum: [unsupported_parameter, selector_conflict, kind_conflict, invalid_parameter] }
                  message: { type: string }
