openapi: 3.1.0
info:
  title: ThumbGate API
  version: 1.2.0
  description: |
    Production API for feedback capture, schema-validated memory promotion,
    prevention rule generation, and DPO export.
    Bare up/down signals are logged immediately, but the API returns
    clarification_required until one sentence explains what worked or failed.
    When the explanation is specific enough, ThumbGate infers a domain tag if
    the caller omitted manual tags so the feedback can still promote cleanly.
servers:
  - url: https://thumbgate-production.up.railway.app
security:
  - bearerAuth: []
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
    humanReviewerKey:
      type: apiKey
      in: header
      name: X-ThumbGate-Human-Reviewer-Key
      description: Independently revocable credential for the server-configured human reviewer identity.
  schemas:
    RubricScore:
      type: object
      required: [criterion, score]
      properties:
        criterion:
          type: string
        score:
          type: number
          minimum: 1
          maximum: 5
        evidence:
          type: string
        judge:
          type: string
    CaptureFeedbackRequest:
      type: object
      required: [signal]
      properties:
        signal:
          type: string
          enum: [up, down, positive, negative]
        context:
          type: string
          description: One-sentence reason describing what worked or failed
        whatWentWrong:
          type: string
        whatToChange:
          type: string
        whatWorked:
          type: string
        rubricScores:
          type: array
          items:
            $ref: '#/components/schemas/RubricScore'
        guardrails:
          type: object
          properties:
            testsPassed:
              type: boolean
            pathSafety:
              type: boolean
            budgetCompliant:
              type: boolean
        tags:
          oneOf:
            - type: array
              items:
                type: string
            - type: string
          description: Optional domain tags. If omitted, ThumbGate infers one from the feedback text before promotion.
        skill:
          type: string
        source:
          type: string
          enum: [chatgpt_gpt]
          default: chatgpt_gpt
          description: Attribution marker for ThumbGate analytics. The published ThumbGate GPT should send `chatgpt_gpt` so owner dashboards can distinguish GPT Action calls from local API calls.
    TaskOutcomeReceipt:
      type: object
      additionalProperties: false
      required: [taskId, goal, status, verification, toolCalls, policy, efficiency]
      properties:
        taskId:
          type: string
        taskType:
          type: string
        goal:
          type: string
        expectedOutcome:
          type: string
        status:
          type: string
          enum: [completed, failed, partial, escalated]
        verification:
          type: object
          required: [performed, passed, evidence]
          properties:
            performed:
              type: boolean
            passed:
              type: boolean
            verifier:
              type: string
            method:
              type: string
            evidence:
              type: array
              items:
                type: string
            unsupportedClaims:
              type: integer
              minimum: 0
        toolCalls:
          type: array
          items:
            type: object
            required: [name, contractValid, allowed, succeeded, attempts]
            properties:
              name:
                type: string
              contractValid:
                type: boolean
              allowed:
                type: boolean
              succeeded:
                type: boolean
              attempts:
                type: integer
                minimum: 1
              idempotencyKey:
                type: string
              duplicateSideEffect:
                type: boolean
        policy:
          type: object
          required: [violations, unsafeEscapes, falseBlocks]
          properties:
            violations:
              type: integer
            unsafeEscapes:
              type: integer
            falseBlocks:
              type: integer
        efficiency:
          type: object
          required: [latencyMs, costUsd]
          properties:
            latencyMs:
              type: number
            costUsd:
              type: number
            firstAttempt:
              type: boolean
        idempotencyKey:
          type: string
    EscalationIdentity:
      type: object
      additionalProperties: false
      required: [id, kind]
      properties:
        id:
          type: string
          minLength: 1
        kind:
          type: string
          enum: [agent, service, human]
        displayName:
          type: string
    HumanEscalationRequest:
      type: object
      additionalProperties: false
      required: [taskId, reason, requester, evidence]
      properties:
        taskId:
          type: string
          minLength: 1
        reason:
          type: string
          minLength: 1
        severity:
          type: string
          enum: [low, medium, high, critical]
        requester:
          $ref: '#/components/schemas/EscalationIdentity'
        evidence:
          type: array
          minItems: 1
          items:
            type: string
            minLength: 1
        ttlMs:
          type: number
          minimum: 1
        idempotencyKey:
          type: string
    HumanEscalationDecision:
      type: object
      additionalProperties: false
      required: [decision, reason]
      properties:
        decision:
          type: string
          enum: [approved, rejected, cancelled]
        reason:
          type: string
          minLength: 1
    IntentPlanRequest:
      type: object
      required: [intentId]
      properties:
        intentId:
          type: string
        context:
          type: string
        mcpProfile:
          type: string
        bundleId:
          type: string
        partnerProfile:
          type: string
        delegationMode:
          type: string
          enum: [off, auto, sequential]
        enforcePlanQuality:
          type: boolean
        approved:
          type: boolean
        repoPath:
          type: string
    InternalAgentBootstrapRequest:
      type: object
      required: [source]
      properties:
        source:
          type: string
          enum: [github, slack, linear, api, cli]
        repoPath:
          type: string
        prepareSandbox:
          type: boolean
        sandboxRoot:
          type: string
        intentId:
          type: string
        context:
          type: string
        mcpProfile:
          type: string
        partnerProfile:
          type: string
        delegationMode:
          type: string
          enum: [off, auto, sequential]
        approved:
          type: boolean
        trigger:
          type: object
          properties:
            type:
              type: string
            id:
              type: string
            url:
              type: string
            actor:
              type: string
        thread:
          type: object
          properties:
            id:
              type: string
            title:
              type: string
            url:
              type: string
        task:
          type: object
          properties:
            title:
              type: string
            body:
              type: string
            number:
              type: string
            branch:
              type: string
            labels:
              type: array
              items:
                type: string
        comments:
          type: array
          items:
            type: object
            properties:
              author:
                type: string
              text:
                type: string
              timestamp:
                type: string
        messages:
          type: array
          items:
            type: object
            properties:
              author:
                type: string
              text:
                type: string
              timestamp:
                type: string
    HandoffStartRequest:
      type: object
      required: [intentId]
      properties:
        intentId:
          type: string
        context:
          type: string
        mcpProfile:
          type: string
        bundleId:
          type: string
        partnerProfile:
          type: string
        approved:
          type: boolean
        repoPath:
          type: string
        delegateProfile:
          type: string
        plannedChecks:
          type: array
          items:
            type: string
    HandoffCompleteRequest:
      type: object
      required: [handoffId, outcome]
      properties:
        handoffId:
          type: string
        outcome:
          type: string
          enum: [accepted, rejected, aborted]
        resultContext:
          type: string
        attempts:
          type: number
        violationCount:
          type: number
        tokenEstimate:
          type: number
        latencyMs:
          type: number
        summary:
          type: string
    BillingCheckoutRequest:
      type: object
      properties:
        successUrl:
          type: string
          format: uri
        cancelUrl:
          type: string
          format: uri
        customerEmail:
          type: string
          format: email
        installId:
          type: string
        metadata:
          type: object
          additionalProperties:
            type: string
    BillingProvisionRequest:
      type: object
      required: [customerId]
      properties:
        customerId:
          type: string
        installId:
          type: string
    WorkflowSprintIntakeRequest:
      type: object
      required: [email, workflow, owner, blocker, runtime]
      properties:
        email:
          type: string
          format: email
        company:
          type: string
        workflow:
          type: string
        owner:
          type: string
        blocker:
          type: string
        runtime:
          type: string
        note:
          type: string
        acquisitionId:
          type: string
        visitorId:
          type: string
        sessionId:
          type: string
        traceId:
          type: string
        installId:
          type: string
        source:
          type: string
        utmSource:
          type: string
        utmMedium:
          type: string
        utmCampaign:
          type: string
        utmContent:
          type: string
        utmTerm:
          type: string
        community:
          type: string
        postId:
          type: string
        commentId:
          type: string
        campaignVariant:
          type: string
        offerCode:
          type: string
        ctaId:
          type: string
        ctaPlacement:
          type: string
        planId:
          type: string
        page:
          type: string
        landingPath:
          type: string
        referrerHost:
          type: string
        referrer:
          type: string
    WorkflowSprintIntakeResponse:
      type: object
      properties:
        ok:
          type: boolean
        leadId:
          type: string
        status:
          type: string
        offer:
          type: string
        nextStep:
          type: string
        proofPackUrl:
          type: string
          format: uri
        sprintBriefUrl:
          type: string
          format: uri
    WorkflowIntakeClosePacket:
      type: object
      required:
        - status
        - leadId
        - blockers
        - verificationPlan
        - externalActionAuthorized
        - revenueRecognized
      properties:
        status:
          type: string
          enum: [approval_ready_not_authorized, hold_not_approval_ready]
        leadId:
          type: string
        destination:
          type: object
          nullable: true
          properties:
            channel:
              type: string
              enum: [email]
            address:
              type: string
              format: email
        offer:
          type: object
          nullable: true
          additionalProperties: true
        draft:
          type: object
          nullable: true
          properties:
            subject:
              type: string
            body:
              type: string
        approvalPhrase:
          type: string
          nullable: true
        blockers:
          type: array
          items:
            type: string
        evidence:
          type: object
          additionalProperties: true
        verificationPlan:
          type: array
          items:
            type: string
        externalActionAuthorized:
          type: boolean
          enum: [false]
        revenueRecognized:
          type: boolean
          enum: [false]
    WorkflowIntakeDiscoveryPacket:
      type: object
      required:
        - type
        - status
        - leadId
        - blockers
        - verificationPlan
        - externalActionAuthorized
        - revenueRecognized
      properties:
        type:
          type: string
          enum: [discovery_questions]
        status:
          type: string
          enum: [approval_ready_not_authorized, hold_not_approval_ready]
        leadId:
          type: string
        destination:
          type: object
          nullable: true
          properties:
            channel:
              type: string
              enum: [email]
            address:
              type: string
              format: email
        draft:
          type: object
          nullable: true
          properties:
            subject:
              type: string
            body:
              type: string
        approvalPhrase:
          type: string
          nullable: true
        blockers:
          type: array
          items:
            type: string
        evidence:
          type: object
          additionalProperties: true
        verificationPlan:
          type: array
          items:
            type: string
        externalActionAuthorized:
          type: boolean
          enum: [false]
        revenueRecognized:
          type: boolean
          enum: [false]
    WorkflowIntakeQueueResponse:
      type: object
      required: [generatedAt, total, eligibleTotal, returned, approvalReadyTotal, discoveryReadyTotal, leads]
      properties:
        generatedAt:
          type: string
          format: date-time
        total:
          type: integer
        eligibleTotal:
          type: integer
        returned:
          type: integer
        approvalReadyTotal:
          type: integer
        discoveryReadyTotal:
          type: integer
        primaryApprovalAction:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/WorkflowIntakeClosePacket'
        primaryDiscoveryAction:
          nullable: true
          allOf:
            - $ref: '#/components/schemas/WorkflowIntakeDiscoveryPacket'
        leads:
          type: array
          items:
            type: object
            additionalProperties: true
    WorkflowSprintAdvanceRequest:
      type: object
      required: [leadId, status]
      properties:
        leadId:
          type: string
        status:
          type: string
          enum: [new, qualified, named_pilot, proof_backed_run, paid_team]
        actor:
          type: string
        note:
          type: string
        reviewedBy:
          type: string
        workflowId:
          type: string
        teamId:
          type: string
        proofArtifacts:
          type: array
          items:
            type: string
        qualificationReview:
          type: object
          description: Required evidence-based buyer qualification review when advancing to qualified.
          required:
            - severityAndFrequency
            - measurableImpact
            - urgencyAndTrigger
            - decisionAuthority
            - budgetMechanism
            - offerFit
            - proofRequired
            - nextStep
            - evidenceReferences
            - zeroSpendStatus
          properties:
            severityAndFrequency:
              type: string
            measurableImpact:
              type: string
            urgencyAndTrigger:
              type: string
            decisionAuthority:
              type: string
            budgetMechanism:
              type: string
            offerFit:
              type: string
            proofRequired:
              type: string
            nextStep:
              type: string
            evidenceReferences:
              type: array
              minItems: 1
              items:
                type: string
            zeroSpendStatus:
              type: string
              enum: [proceed_zero_cost]
            priceUnderstandingConfirmed:
              type: boolean
            workflowCount:
              type: integer
              minimum: 1
            authorityConfirmed:
              type: boolean
            urgencyDays:
              type: integer
              minimum: 1
            budgetCents:
              type: integer
              minimum: 0
            readyToImplement:
              type: boolean
            proofBackedSprint:
              type: boolean
            completedEnterprisePilot:
              type: boolean
            requiresUnavailableHostedFeature:
              type: boolean
    WorkflowSprintAdvanceResponse:
      type: object
      properties:
        ok:
          type: boolean
        unchanged:
          type: boolean
        lead:
          type: object
          additionalProperties: true
        workflowRun:
          type: object
          nullable: true
          additionalProperties: true
    FunnelAnalyticsResponse:
      type: object
      properties:
        totalEvents:
          type: integer
        stageCounts:
          type: object
          properties:
            acquisition:
              type: integer
            activation:
              type: integer
            paid:
              type: integer
        eventCounts:
          type: object
          additionalProperties:
            type: integer
        conversionRates:
          type: object
          properties:
            acquisitionToActivation:
              type: number
            activationToPaid:
              type: number
            acquisitionToPaid:
              type: number
        paidProviderEvents:
          type: integer
    BillingSummaryResponse:
      type: object
      properties:
        generatedAt:
          type: string
          format: date-time
        coverage:
          type: object
          properties:
            source:
              type: string
            tracksBookedRevenue:
              type: boolean
            tracksPaidOrders:
              type: boolean
            tracksInvoices:
              type: boolean
            tracksAttribution:
              type: boolean
            providerCoverage:
              type: object
              additionalProperties:
                type: string
        funnel:
          allOf:
            - $ref: '#/components/schemas/FunnelAnalyticsResponse'
            - type: object
              properties:
                uniqueAcquisitionLeads:
                  type: integer
                uniquePaidCustomers:
                  type: integer
                firstPaidAt:
                  type: string
                  nullable: true
                lastPaidAt:
                  type: string
                  nullable: true
                lastPaidEvent:
                  type: object
                  nullable: true
                  properties:
                    timestamp:
                      type: string
                      nullable: true
                    event:
                      type: string
                      nullable: true
                    evidence:
                      type: string
                      nullable: true
                    customerId:
                      type: string
                      nullable: true
                    traceId:
                      type: string
                      nullable: true
        signups:
          type: object
          properties:
            total:
              type: integer
            uniqueLeads:
              type: integer
            bySource:
              type: object
              additionalProperties:
                type: integer
            byCampaign:
              type: object
              additionalProperties:
                type: integer
        pipeline:
          type: object
          properties:
            workflowSprintLeads:
              type: object
              properties:
                total:
                  type: integer
                bySource:
                  type: object
                  additionalProperties:
                    type: integer
            qualifiedWorkflowSprintLeads:
              type: object
              properties:
                total:
                  type: integer
                bySource:
                  type: object
                  additionalProperties:
                    type: integer
        revenue:
          type: object
          properties:
            paidProviderEvents:
              type: integer
            paidOrders:
              type: integer
            paidCustomers:
              type: integer
            bookedRevenueCents:
              type: integer
            bookedRevenueByCurrency:
              type: object
              additionalProperties:
                type: integer
            amountKnownOrders:
              type: integer
            amountUnknownOrders:
              type: integer
            amountKnownCoverageRate:
              type: number
            unreconciledPaidEvents:
              type: integer
            latestPaidAt:
              type: string
              nullable: true
            latestPaidOrder:
              type: object
              nullable: true
              properties:
                timestamp:
                  type: string
                  nullable: true
                provider:
                  type: string
                  nullable: true
                event:
                  type: string
                  nullable: true
                orderId:
                  type: string
                  nullable: true
                customerId:
                  type: string
                  nullable: true
                amountCents:
                  type: integer
                  nullable: true
                currency:
                  type: string
                  nullable: true
                amountKnown:
                  type: boolean
            byProvider:
              type: object
              additionalProperties:
                type: object
                properties:
                  paidOrders:
                    type: integer
                  bookedRevenueCents:
                    type: integer
                  amountKnownOrders:
                    type: integer
                  amountUnknownOrders:
                    type: integer
                  bookedRevenueByCurrency:
                    type: object
                    additionalProperties:
                      type: integer
        attribution:
          type: object
          properties:
            acquisitionBySource:
              type: object
              additionalProperties:
                type: integer
            acquisitionByCampaign:
              type: object
              additionalProperties:
                type: integer
            paidBySource:
              type: object
              additionalProperties:
                type: integer
            paidByCampaign:
              type: object
              additionalProperties:
                type: integer
            bookedRevenueBySourceCents:
              type: object
              additionalProperties:
                type: integer
            bookedRevenueByCampaignCents:
              type: object
              additionalProperties:
                type: integer
            conversionBySource:
              type: object
              additionalProperties:
                type: number
            conversionByCampaign:
              type: object
              additionalProperties:
                type: number
        keys:
          type: object
          properties:
            total:
              type: integer
            active:
              type: integer
            disabled:
              type: integer
            activeCustomers:
              type: integer
            totalUsage:
              type: integer
            bySource:
              type: object
              additionalProperties:
                type: integer
            activeBySource:
              type: object
              additionalProperties:
                type: integer
        customers:
          type: array
          items:
            type: object
            properties:
              customerId:
                type: string
              activeKeys:
                type: integer
              totalKeys:
                type: integer
              usageCount:
                type: integer
              source:
                type: string
              installId:
                type: string
                nullable: true
              createdAt:
                type: string
                nullable: true
              disabledAt:
                type: string
                nullable: true
        trafficMetrics:
          type: object
          properties:
            visitors:
              type: integer
            sessions:
              type: integer
            pageViews:
              type: integer
            ctaClicks:
              type: integer
            checkoutStarts:
              type: integer
            buyerLossFeedback:
              type: integer
            seoLandingViews:
              type: integer
        operatorGeneratedAcquisition:
          type: object
          properties:
            totalEvents:
              type: integer
            uniqueLeads:
              type: integer
            bySource:
              type: object
              additionalProperties:
                type: integer
        dataQuality:
          type: object
          properties:
            telemetryCoverage:
              type: number
            attributionCoverage:
              type: number
            amountKnownCoverage:
              type: number
            unreconciledPaidEvents:
              type: integer
paths:
  /healthz:
    get:
      operationId: healthz
      responses:
        '200':
          description: Service health
        '401':
          description: Unauthorized
  /v1/feedback/capture:
    post:
      operationId: captureFeedback
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CaptureFeedbackRequest'
      responses:
        '200':
          description: Feedback accepted and promoted to memory
        '422':
          description: Feedback logged only; clarification required or promotion rejected
        '401':
          description: Unauthorized
  /v1/feedback/stats:
    get:
      operationId: getFeedbackStats
      responses:
        '200':
          description: Aggregated feedback statistics
        '401':
          description: Unauthorized
  /v1/feedback/infer:
    post:
      operationId: inferLessonFromHistory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InferLessonRequest'
      responses:
        '200':
          description: Distilled lesson from chat history
        '401':
          description: Unauthorized
  /v1/telemetry/ping:
    post:
      operationId: recordTelemetryPing
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        '204':
          description: Telemetry accepted on a best-effort basis
  /v1/analytics/funnel:
    get:
      operationId: getFunnelAnalytics
      responses:
        '200':
          description: Acquisition/activation/paid funnel metrics from append-only ledger
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FunnelAnalyticsResponse'
        '401':
          description: Unauthorized
  /v1/analytics/losses:
    get:
      operationId: getLossAnalytics
      parameters:
        - in: query
          name: window
          schema:
            type: string
            enum: [today, 7d, 30d, lifetime]
        - in: query
          name: timezone
          schema:
            type: string
        - in: query
          name: now
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Ranked buyer-loss and revenue-opportunity analysis for the active analytics window
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
  /v1/dashboard:
    get:
      operationId: getDashboard
      parameters:
        - in: query
          name: window
          schema:
            type: string
            enum: [today, 7d, 30d, lifetime]
        - in: query
          name: timezone
          schema:
            type: string
        - in: query
          name: now
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Full ThumbGate dashboard with feedback, telemetry, funnel, and observability analytics
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
  /v1/dashboard/review-state:
    get:
      operationId: getDashboardReviewState
      responses:
        '200':
          description: Persisted dashboard review checkpoint and the current delta since that checkpoint
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
    post:
      operationId: markDashboardReviewed
      responses:
        '200':
          description: Persist and return the current dashboard review checkpoint
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
  /v1/dashboard/render-spec:
    get:
      operationId: getDashboardRenderSpec
      parameters:
        - in: query
          name: view
          schema:
            type: string
            enum: [team-review, incident-review, workflow-rollout]
        - in: query
          name: window
          schema:
            type: string
            enum: [today, 7d, 30d, lifetime]
        - in: query
          name: timezone
          schema:
            type: string
        - in: query
          name: now
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Constrained JSON render spec for hosted Team and operations dashboard views
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Invalid dashboard render view or query
        '401':
          description: Unauthorized
  /v1/decisions/evaluate:
    post:
      operationId: evaluateDecision
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                toolName:
                  type: string
                  description: Tool name is optional when provider-native tool call payload is supplied.
                source:
                  type: string
                  enum: [chatgpt_gpt]
                  default: chatgpt_gpt
                  description: Attribution marker for ThumbGate analytics. The published ThumbGate GPT should send `chatgpt_gpt` so owner dashboards can distinguish GPT Action calls from local API calls.
                provider:
                  type: string
                model:
                  type: string
                providerToolCall:
                  type: object
                  additionalProperties: true
                toolCall:
                  type: object
                  additionalProperties: true
                toolUse:
                  type: object
                  additionalProperties: true
                content:
                  type: array
                  items:
                    type: object
                    additionalProperties: true
                input:
                  type: object
                  additionalProperties: true
                arguments:
                  type: object
                  additionalProperties: true
                method:
                  type: string
                params:
                  type: object
                  additionalProperties: true
                mcp:
                  type: object
                  additionalProperties: true
                mcpToolCall:
                  type: object
                  additionalProperties: true
                usage:
                  type: object
                  additionalProperties: true
                tokenEstimate:
                  type: number
                costUsd:
                  type: number
                budget:
                  type: object
                  additionalProperties: true
                workflowPattern:
                  type: string
                  enum: [single_action, chaining, routing, parallelization, evaluator-optimizer, agent]
                workflow:
                  type: object
                  additionalProperties: true
                goal:
                  type: string
                tools:
                  type: array
                  items:
                    type: string
                branches:
                  type: array
                  items:
                    type: string
                steps:
                  type: array
                  items:
                    type: string
                routes:
                  type: array
                  items:
                    type: string
                command:
                  type: string
                filePath:
                  type: string
                changedFiles:
                  type: array
                  items:
                    type: string
                repoPath:
                  type: string
                baseBranch:
                  type: string
                requirePrForReleaseSensitive:
                  type: boolean
                requireVersionNotBehindBase:
                  type: boolean
                workflowDispatch:
                  type: object
                  description: Evidence required before running `gh workflow run` or another environment-specific workflow dispatch.
                  properties:
                    environment:
                      type: string
                      description: Requested environment such as dev, staging, beta, or release.
                    workflow:
                      type: string
                      description: Expected workflow file or workflow name.
                    ref:
                      type: string
                      description: Expected branch or ref passed to the workflow dispatch command.
                    sha:
                      type: string
                      description: Expected HEAD SHA to verify before and after dispatch.
                    job:
                      type: string
                      description: Expected job name to verify before reporting the workflow URL.
      responses:
        '200':
          description: Persisted workflow-sentinel recommendation with decision-control metadata and actionId
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Invalid decision evaluation request
        '401':
          description: Unauthorized
  /v1/decisions/outcome:
    post:
      operationId: recordDecisionOutcome
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [actionId, outcome]
              properties:
                actionId:
                  type: string
                outcome:
                  type: string
                actualDecision:
                  type: string
                actor:
                  type: string
                notes:
                  type: string
                latencyMs:
                  type: number
                metadata:
                  type: object
                  additionalProperties: true
      responses:
        '200':
          description: Recorded a decision override, rollback, completion, or block outcome
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          description: Invalid decision outcome request
        '401':
          description: Unauthorized
  /v1/decisions/metrics:
    get:
      operationId: getDecisionMetrics
      responses:
        '200':
          description: Decision-loop metrics derived from recorded evaluations and outcomes
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
  /v1/settings/status:
    get:
      operationId: getSettingsStatus
      responses:
        '200':
          description: Resolved settings hierarchy with per-field origin metadata for managed, user, project, and local scopes
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          description: Unauthorized
  /v1/billing/summary:
    get:
      operationId: getBillingSummary
      responses:
        '200':
          description: Admin-only business summary from the funnel ledger, revenue ledger, and key store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BillingSummaryResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /v1/intake/workflow-sprint:
    post:
      operationId: submitWorkflowSprintIntake
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowSprintIntakeRequest'
      responses:
        '201':
          description: Workflow Hardening Sprint lead accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowSprintIntakeResponse'
        '400':
          description: Invalid sprint intake request
  /v1/intake/workflow-sprint/queue:
    get:
      operationId: getWorkflowSprintCloseQueue
      parameters:
        - in: query
          name: status
          description: Comma-separated workflow lifecycle statuses or all.
          schema:
            type: string
            default: new,qualified
        - in: query
          name: limit
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
      responses:
        '200':
          description: Private no-store intake queue with fail-closed approval packets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowIntakeQueueResponse'
        '400':
          description: Invalid queue filter
        '403':
          description: Forbidden
        '503':
          description: Workflow intake capability is unavailable in this runtime
  /v1/intake/workflow-sprint/advance:
    post:
      operationId: advanceWorkflowSprintLead
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowSprintAdvanceRequest'
      responses:
        '200':
          description: Workflow Hardening Sprint lead advanced to the next state
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowSprintAdvanceResponse'
        '400':
          description: Invalid sprint advancement request
        '403':
          description: Forbidden
  /v1/intents/catalog:
    get:
      operationId: listIntentCatalog
      parameters:
        - in: query
          name: mcpProfile
          schema:
            type: string
        - in: query
          name: bundleId
          schema:
            type: string
        - in: query
          name: partnerProfile
          schema:
            type: string
      responses:
        '200':
          description: Intent catalog with risk and checkpoint metadata
        '401':
          description: Unauthorized
  /v1/intents/plan:
    post:
      operationId: planIntent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IntentPlanRequest'
      responses:
        '200':
          description: Policy-scoped intent execution plan
        '400':
          description: Invalid intent request
        '401':
          description: Unauthorized
  /v1/handoffs/start:
    post:
      operationId: startHandoff
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HandoffStartRequest'
      responses:
        '200':
          description: Sequential handoff started
        '400':
          description: Invalid handoff request
        '401':
          description: Unauthorized
  /v1/handoffs/complete:
    post:
      operationId: completeHandoff
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HandoffCompleteRequest'
      responses:
        '200':
          description: Sequential handoff completed
        '400':
          description: Invalid handoff completion request
        '401':
          description: Unauthorized
  /v1/internal-agent/bootstrap:
    post:
      operationId: bootstrapInternalAgent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InternalAgentBootstrapRequest'
      responses:
        '200':
          description: Normalized trigger context, recall pack, sandbox, and reviewer-ready execution plan
        '400':
          description: Invalid internal-agent bootstrap request
        '401':
          description: Unauthorized
  /v1/feedback/summary:
    get:
      operationId: getFeedbackSummary
      parameters:
        - in: query
          name: recent
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Feedback summary text
        '401':
          description: Unauthorized
  /v1/lessons/search:
    get:
      operationId: searchLessons
      parameters:
        - in: query
          name: q
          schema:
            type: string
          description: Search query. Leave empty to list recent lessons.
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
        - in: query
          name: category
          schema:
            type: string
            enum: [error, learning, preference]
        - in: query
          name: tags
          schema:
            type: string
          description: Comma-separated tags that must all be present on a lesson.
      responses:
        '200':
          description: Searchable promoted lessons with linked corrective actions, prevention rules, and auto-promoted checks
        '401':
          description: Unauthorized
  /v1/search:
    get:
      operationId: searchThumbgate
      parameters:
        - in: query
          name: q
          schema:
            type: string
          description: Search query for raw ThumbGate state.
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
        - in: query
          name: source
          schema:
            type: string
            enum: [all, feedback, context, rules]
            default: all
        - in: query
          name: signal
          schema:
            type: string
            enum: [up, down, positive, negative]
      responses:
        '200':
          description: Search results across feedback logs, ContextFS, and prevention rules
        '401':
          description: Unauthorized
    post:
      operationId: searchThumbgatePost
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  type: string
                q:
                  type: string
                limit:
                  type: integer
                  default: 10
                source:
                  type: string
                  enum: [all, feedback, context, rules]
                  default: all
                signal:
                  type: string
                  enum: [up, down, positive, negative]
      responses:
        '200':
          description: Search results across feedback logs, ContextFS, and prevention rules
        '401':
          description: Unauthorized
  /v1/feedback/rules:
    post:
      operationId: generatePreventionRules
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                minOccurrences:
                  type: integer
                  default: 2
                outputPath:
                  type: string
      responses:
        '200':
          description: Prevention rules generated
        '401':
          description: Unauthorized
  /v1/dpo/export:
    post:
      operationId: exportDpoPairs
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                inputPath:
                  type: string
                memoryLogPath:
                  type: string
                outputPath:
                  type: string
                async:
                  type: boolean
                mode:
                  type: string
                  enum: [sync, async]
                jobId:
                  type: string
      responses:
        '200':
          description: DPO export completed
        '202':
          description: DPO export accepted as a hosted background job
        '401':
          description: Unauthorized
  /v1/documents:
    get:
      operationId: listImportedDocuments
      parameters:
        - in: query
          name: query
          schema:
            type: string
        - in: query
          name: q
          schema:
            type: string
        - in: query
          name: tag
          schema:
            type: string
        - in: query
          name: limit
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Imported policy and runbook documents
        '401':
          description: Unauthorized
  /v1/documents/import:
    post:
      operationId: importDocument
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                filePath:
                  type: string
                content:
                  type: string
                title:
                  type: string
                sourceFormat:
                  type: string
                  enum: [markdown, text, yaml, json, html]
                sourceUrl:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
                proposeGates:
                  type: boolean
      responses:
        '201':
          description: Document imported
        '400':
          description: Invalid document import request
        '401':
          description: Unauthorized
  /v1/documents/{documentId}:
    get:
      operationId: getImportedDocument
      parameters:
        - in: path
          name: documentId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Imported document with proposed gates
        '401':
          description: Unauthorized
        '404':
          description: Imported document not found
  /v1/jobs:
    get:
      operationId: listHostedJobs
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 20
        - in: query
          name: status
          schema:
            type: string
          description: Optional comma-separated list of job statuses to filter.
      responses:
        '200':
          description: Hosted job states
        '401':
          description: Unauthorized
  /v1/jobs/harness:
    post:
      operationId: launchHostedHarness
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [harness]
              properties:
                harness:
                  type: string
                harnessId:
                  type: string
                jobId:
                  type: string
                skill:
                  type: string
                partnerProfile:
                  type: string
                autoImprove:
                  type: boolean
                inputs:
                  type: object
      responses:
        '202':
          description: Hosted harness accepted
        '401':
          description: Unauthorized
  /v1/jobs/{jobId}:
    get:
      operationId: getHostedJob
      parameters:
        - in: path
          name: jobId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Hosted job state
        '401':
          description: Unauthorized
        '404':
          description: Job not found
  /v1/jobs/{jobId}/control:
    post:
      operationId: controlHostedJob
      parameters:
        - in: path
          name: jobId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [action]
              properties:
                action:
                  type: string
                  enum: [pause, cancel, resume]
                metadata:
                  type: object
      responses:
        '202':
          description: Hosted job control accepted
        '401':
          description: Unauthorized
        '404':
          description: Job not found
        '409':
          description: Job cannot accept the requested control action
  /v1/analytics/databricks/export:
    post:
      operationId: exportDatabricksBundle
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                outputPath:
                  type: string
      responses:
        '200':
          description: Databricks bundle exported
        '401':
          description: Unauthorized
  /v1/context/construct:
    post:
      operationId: constructContextPack
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  type: string
                maxItems:
                  type: integer
                  default: 8
                maxChars:
                  type: integer
                  default: 6000
                namespaces:
                  type: array
                  items:
                    type: string
                    enum:
                      - raw_history
                      - memory/error
                      - memory/learning
                      - rules
                      - tools
                      - provenance
      responses:
        '200':
          description: Context pack created
        '400':
          description: Invalid namespace selection
        '401':
          description: Unauthorized
  /v1/context/evaluate:
    post:
      operationId: evaluateContextPack
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [packId, outcome]
              properties:
                packId:
                  type: string
                outcome:
                  type: string
                signal:
                  type: string
                notes:
                  type: string
                rubricScores:
                  type: array
                  items:
                    $ref: '#/components/schemas/RubricScore'
                guardrails:
                  type: object
                  properties:
                    testsPassed:
                      type: boolean
                    pathSafety:
                      type: boolean
                    budgetCompliant:
                      type: boolean
      responses:
        '200':
          description: Evaluation recorded
        '400':
          description: Invalid rubric payload
        '401':
          description: Unauthorized
  /v1/context/provenance:
    get:
      operationId: getContextProvenance
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 50
      responses:
        '200':
          description: Recent provenance events
        '401':
          description: Unauthorized
  /v1/billing/checkout:
    post:
      operationId: createBillingCheckoutSession
      security: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BillingCheckoutRequest'
      responses:
        '200':
          description: Stripe checkout session created
  /v1/billing/usage:
    get:
      operationId: getBillingUsage
      responses:
        '200':
          description: Usage count for authenticated billing key
        '401':
          description: Unauthorized
  /v1/billing/provision:
    post:
      operationId: provisionBillingKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BillingProvisionRequest'
      responses:
        '200':
          description: API key provisioned
        '400':
          description: Missing required customerId
        '401':
          description: Unauthorized
        '403':
          description: Forbidden - requires static THUMBGATE_API_KEY admin token
  /v1/billing/webhook:
    post:
      operationId: stripeBillingWebhook
      security: []
      responses:
        '200':
          description: Webhook accepted
        '400':
          description: Invalid webhook signature or payload
  /v1/billing/github-webhook:
    post:
      operationId: githubMarketplaceWebhook
      security: []
      responses:
        '200':
          description: Webhook accepted
        '400':
          description: Invalid webhook signature or payload
  /v1/billing/paypal-webhook:
    post:
      operationId: paypalBillingWebhook
      security: []
      responses:
        '200':
          description: PayPal-verified payment event durably recorded
        '400':
          description: Invalid PayPal transmission headers, event, or remote signature verification
        '503':
          description: PayPal verified the event but durable evidence storage failed
  /v1/task-outcomes:
    post:
      operationId: recordTaskOutcome
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TaskOutcomeReceipt'
      responses:
        '201':
          description: Task outcome recorded
        '400':
          description: Invalid or conflicting task outcome
        '401':
          description: Unauthorized
    get:
      operationId: listTaskOutcomes
      parameters:
        - in: query
          name: taskId
          schema:
            type: string
        - in: query
          name: limit
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Task outcomes
        '401':
          description: Unauthorized
  /v1/task-outcomes/metrics:
    get:
      operationId: getTaskOutcomeMetrics
      responses:
        '200':
          description: Transparent task, tool, safety, escalation, cost, latency, and business metrics
        '401':
          description: Unauthorized
  /v1/task-outcomes/monitor:
    get:
      operationId: monitorTaskOutcomes
      responses:
        '200':
          description: Production task outcome threshold verdict
        '401':
          description: Unauthorized
  /v1/escalations:
    post:
      operationId: requestHumanEscalation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HumanEscalationRequest'
      responses:
        '201':
          description: Human escalation requested
        '400':
          description: Invalid or conflicting request
        '401':
          description: Unauthorized
    get:
      operationId: listHumanEscalations
      responses:
        '200':
          description: Human escalation queue and metrics
        '401':
          description: Unauthorized
  /v1/escalations/{escalationId}/decision:
    post:
      operationId: decideHumanEscalation
      security:
        - bearerAuth: []
          humanReviewerKey: []
      parameters:
        - in: path
          name: escalationId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HumanEscalationDecision'
      responses:
        '200':
          description: Human escalation decision recorded
        '400':
          description: Invalid decision or the authenticated reviewer matches the requester
        '401':
          description: Unauthorized
        '403':
          description: Missing or invalid human reviewer credential
        '503':
          description: Human reviewer identity is not configured
