openapi: 3.1.0
info:
  title: AgentKit API
  version: 1.0.0
  description: |
    API for AgentKit services. Provides access to AI-powered video processing via VidCap.xyz
    and SEO auditing via ReviewWeb.site through secure proxy endpoints.

    ## Authentication
    All proxy endpoints require a valid AgentKit API key passed in the `X-API-Key` header.
    API keys can be created and managed via the dashboard or the `/api/keys` endpoints.

    ## Rate Limiting
    API requests are rate-limited based on your subscription plan.
    Rate limit headers are included in all responses.
  contact:
    name: AgentKit Support
    email: support@agentkit.best
    url: https://agentkit.best
  license:
    name: Proprietary
    url: https://agentkit.best/terms

servers:
  - url: https://agentkit.best/api
    description: Production
  - url: http://localhost:3000/api
    description: Local Development

security:
  - ApiKeyAuth: []

tags:
  - name: API Keys
    description: Manage your API keys
  - name: Referrals
    description: Referral dashboard and conversion list endpoints
  - name: AgentKit Feedback
    description: AgentKit client feedback intake
  - name: Build with AK - Listings
    description: Customer product showcase listing and draft revision management endpoints
  - name: Build with AK - Media
    description: Media upload intent authorization and finalization for product listings
  - name: Build with AK - Directory
    description: Public customer product directory, community upvotes, and outbound engagement telemetry
  - name: VidCap - Health
    description: VidCap service health and model endpoints
  - name: VidCap - YouTube
    description: YouTube video processing endpoints
  - name: VidCap - Video
    description: Video retrieval and processing
  - name: ReviewWeb - Health
    description: ReviewWeb service health and profile endpoints
  - name: ReviewWeb - Screenshots
    description: Webpage screenshot capture
  - name: ReviewWeb - Reviews
    description: Website review endpoints
  - name: ReviewWeb - Scraping
    description: Web scraping and link extraction
  - name: ReviewWeb - Extraction
    description: Content extraction from URLs
  - name: ReviewWeb - Conversion
    description: URL to markdown conversion
  - name: ReviewWeb - Summarization
    description: AI-powered URL and website summarization
  - name: ReviewWeb - SEO
    description: SEO insights and analysis

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: AgentKit API key (ck_...)
    BearerAuth:
      type: http
      scheme: bearer
      description: Session token for dashboard endpoints
    BuildWithAkDelegatedAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "API-audience OAuth token issued through confidential hosted MCP token exchange. MCP-audience tokens are not accepted directly. Reads require build-with-ak:read; mutations require build-with-ak:write."
    CookieAuth:
      type: apiKey
      in: cookie
      name: session
      description: Authenticated dashboard session cookie

  schemas:
    BuildWithAkAnalyticsCounts:
      type: object
      additionalProperties: false
      required:
        - views
        - outboundClicks
        - referralConversions
      properties:
        views:
          type: integer
          minimum: 0
          description: Views deduplicated per listing, IP + user-agent fingerprint and UTC day; not monthly unique users.
        outboundClicks:
          type: integer
          minimum: 0
          description: Outbound redirect requests including repeats, not unique visitors.
        referralConversions:
          type: 'null'
          description: Unavailable; conversion tracking has no production writer. Do not infer conversion rates or external product sales.
    BuildWithAkAnalyticsResponse:
      type: object
      additionalProperties: false
      required:
        - listing
        - period
        - source
        - generatedAt
        - totals
        - daily
      properties:
        listing:
          type: object
          required:
            - id
            - slug
          properties:
            id:
              type: string
              format: uuid
            slug:
              type: string
        period:
          type: object
          required:
            - from
            - to
            - timezone
          properties:
            from:
              type: string
              format: date
            to:
              type: string
              format: date
            timezone:
              type: string
              enum:
                - UTC
        source:
          type: string
          enum:
            - first_party_postgresql
        generatedAt:
          type: string
          format: date-time
        totals:
          $ref: '#/components/schemas/BuildWithAkAnalyticsCounts'
        daily:
          type: array
          minItems: 1
          maxItems: 366
          description: Ascending inclusive UTC calendar dates, zero-filled when no events are recorded.
          items:
            type: object
            additionalProperties: false
            required:
              - date
              - views
              - outboundClicks
              - referralConversions
            properties:
              date:
                type: string
                format: date
              views:
                type: integer
                minimum: 0
                description: Views deduplicated per listing, IP + user-agent fingerprint and UTC day; not monthly unique users.
              outboundClicks:
                type: integer
                minimum: 0
                description: Outbound redirect requests including repeats, not unique visitors.
              referralConversions:
                type: 'null'
                description: Unavailable; conversion tracking has no production writer. Do not infer conversion rates or external product sales.
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message
        code:
          type: string
          description: Error code for programmatic handling
      required:
        - error

    FeedbackRequest:
      type: object
      required:
        - schemaVersion
        - type
        - title
        - renderedBody
        - fields
      properties:
        schemaVersion:
          type: integer
          const: 1
        type:
          type: string
          enum: [bug, feature, enhancement]
        title:
          type: string
          minLength: 1
          maxLength: 160
        renderedBody:
          type: string
          maxLength: 60000
          description: Client-rendered preview body. Server redacts but does not re-render.
        fields:
          type: object
          additionalProperties:
            type: string
          properties:
            area:
              type: string
              maxLength: 120
            body:
              type: string
              maxLength: 20000
            repro:
              type: string
              maxLength: 20000
            expected:
              type: string
              maxLength: 20000
            actual:
              type: string
              maxLength: 20000
            outcome:
              type: string
              maxLength: 20000
            motivation:
              type: string
              maxLength: 20000
        clientVersion:
          type: string
          maxLength: 160
        platform:
          type: string
          maxLength: 160
        diagnosticsSummary:
          type: string
          maxLength: 40000

    FeedbackResponse:
      type: object
      required:
        - schemaVersion
        - issueUrl
        - issueNumber
      properties:
        schemaVersion:
          type: integer
          const: 1
        issueUrl:
          type: string
          format: uri
        issueNumber:
          type: integer

    FeedbackError:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          enum: [not_live, unauthorized, rate_limited, invalid, network]
        message:
          type: string
        retryAfter:
          type: string
          description: Seconds until retry, present for rate_limited responses.

    ApiKey:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          maxLength: 100
        prefix:
          type: string
          description: Key prefix for identification (e.g., ck_abc123)
        keyPreview:
          type: string
          description: Masked key preview (e.g., ck_abc123...****)
        rateLimit:
          type: integer
          description: Requests per minute
        isActive:
          type: boolean
        lastUsedAt:
          type:
            - string
            - 'null'
          format: date-time
        usageCount:
          type: integer
        expiresAt:
          type:
            - string
            - 'null'
          format: date-time
        createdAt:
          type: string
          format: date-time

    ApiKeyCreate:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Friendly name for the API key
      required:
        - name

    ApiKeyCreated:
      type: object
      properties:
        id:
          type: string
          format: uuid
        key:
          type: string
          description: Full API key (only shown once on creation)
        name:
          type: string
        message:
          type: string

    ValidationResult:
      type: object
      properties:
        valid:
          type: boolean
        userId:
          type: string
          format: uuid
        rateLimit:
          type: integer
        isActive:
          type: boolean

    ReferralReferee:
      type: object
      properties:
        commissionId:
          type: string
          format: uuid
        status:
          type: string
          enum: [pending, approved, paid, cancelled]
        amount:
          type: integer
          description: Commission amount in cents
        currency:
          type: string
          example: USD
        createdAt:
          type: string
          format: date-time
        approvedAt:
          type:
            - string
            - 'null'
          format: date-time
        paidAt:
          type:
            - string
            - 'null'
          format: date-time
        order:
          type: object
          properties:
            displayId:
              type: string
              description: Non-authoritative display prefix, not the full order UUID
            productType:
              type:
                - string
                - 'null'
            status:
              type:
                - string
                - 'null'
              description: Opaque order state for display
        referee:
          type: object
          properties:
            name:
              type:
                - string
                - 'null'
            avatarUrl:
              type:
                - string
                - 'null'
              format: uri
            emailMasked:
              type:
                - string
                - 'null'
              description: Masked email only; raw email is never returned
      required:
        - commissionId
        - status
        - amount
        - currency
        - createdAt
        - order
        - referee

    ReferralRefereesResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ReferralReferee'
        pagination:
          type: object
          properties:
            limit:
              type: integer
            offset:
              type: integer
            total:
              type: integer
            hasMore:
              type: boolean
          required: [limit, offset, total, hasMore]
        filters:
          type: object
          properties:
            status:
              type: string
              enum: [all, pending, approved, paid, cancelled]
            sort:
              type: string
              enum: [createdAt, amount, status]
            order:
              type: string
              enum: [asc, desc]
            orderRef:
              type: string
              description: Optional exact order display id used to filter rows
          required: [status, sort, order]
      required:
        - data
        - pagination
        - filters

    YouTubeInfo:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        description:
          type: string
        channel:
          type: string
        duration:
          type: integer
        thumbnail:
          type: string
          format: uri

    YouTubeMedia:
      type: object
      properties:
        formats:
          type: array
          items:
            type: object
            properties:
              itag:
                type: integer
              quality:
                type: string
              mimeType:
                type: string
              contentLength:
                type: string

    YouTubeSummary:
      type: object
      properties:
        summary:
          type: string
        keyPoints:
          type: array
          items:
            type: string
        duration:
          type: integer

    YouTubeArticle:
      type: object
      properties:
        title:
          type: string
        content:
          type: string
          description: Markdown formatted article content
        wordCount:
          type: integer

    YouTubeCaption:
      type: object
      properties:
        captions:
          type: array
          items:
            type: object
            properties:
              text:
                type: string
              start:
                type: number
              duration:
                type: number
        language:
          type: string

    YouTubeScreenshot:
      type: object
      properties:
        url:
          type: string
          format: uri
        timestamp:
          type: number

    YouTubeComments:
      type: object
      properties:
        comments:
          type: array
          items:
            type: object
            properties:
              author:
                type: string
              text:
                type: string
              likes:
                type: integer
              publishedAt:
                type: string
        nextPageToken:
          type:
            - string
            - 'null'

    YouTubeSearchResult:
      type: object
      properties:
        results:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              title:
                type: string
              channel:
                type: string
              thumbnail:
                type: string
        nextPageToken:
          type:
            - string
            - 'null'

    HealthCheck:
      type: object
      properties:
        status:
          type: string
          enum: [ok, degraded, down]
        version:
          type: string

    AIModels:
      type: object
      properties:
        models:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              name:
                type: string
              description:
                type: string

    # ReviewWeb Schemas
    ReviewWebProfile:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
        credits:
          type: integer
        plan:
          type: string

    ReviewWebScreenshot:
      type: object
      properties:
        id:
          type: string
        url:
          type: string
          format: uri
        imageUrl:
          type: string
          format: uri
        width:
          type: integer
        height:
          type: integer
        createdAt:
          type: string
          format: date-time

    ReviewWebReview:
      type: object
      properties:
        id:
          type: string
        url:
          type: string
          format: uri
        status:
          type: string
          enum: [pending, processing, completed, failed]
        results:
          type: object
        createdAt:
          type: string
          format: date-time

    ScrapeResult:
      type: object
      properties:
        url:
          type: string
          format: uri
        title:
          type: string
        content:
          type: string
        html:
          type: string
        metadata:
          type: object

    ExtractResult:
      type: object
      properties:
        url:
          type: string
          format: uri
        title:
          type: string
        content:
          type: string
        author:
          type:
            - string
            - 'null'
        publishedDate:
          type:
            - string
            - 'null'

    MarkdownResult:
      type: object
      properties:
        url:
          type: string
          format: uri
        markdown:
          type: string
        title:
          type: string

    SummarizeResult:
      type: object
      properties:
        url:
          type: string
          format: uri
        summary:
          type: string
        keyPoints:
          type: array
          items:
            type: string

    UrlCheckResult:
      type: object
      properties:
        url:
          type: string
          format: uri
        isAlive:
          type: boolean
        statusCode:
          type: integer
        responseTime:
          type: number

    SeoBacklinks:
      type: object
      properties:
        domain:
          type: string
        totalBacklinks:
          type: integer
        backlinks:
          type: array
          items:
            type: object
            properties:
              sourceUrl:
                type: string
              targetUrl:
                type: string
              anchorText:
                type: string

    SeoKeywordIdeas:
      type: object
      properties:
        keyword:
          type: string
        ideas:
          type: array
          items:
            type: object
            properties:
              keyword:
                type: string
              searchVolume:
                type: integer
              difficulty:
                type: number

    SeoTraffic:
      type: object
      properties:
        domain:
          type: string
        estimatedTraffic:
          type: integer
        topPages:
          type: array
          items:
            type: object
            properties:
              url:
                type: string
              traffic:
                type: integer

    BuildWithAkUploadIntentRequest:
      type: object
      required:
        - kind
        - mimeType
      properties:
        kind:
          type: string
          enum: [logo, cover, screenshot]
          description: Media asset kind
        mimeType:
          type: string
          enum: [image/png, image/jpeg, image/webp]
          description: Image MIME type

    BuildWithAkUploadIntentResponse:
      type: object
      required:
        - intentId
        - presignedUrl
        - stagingKey
        - maxByteSize
        - expiresIn
      properties:
        intentId:
          type: string
          format: uuid
          description: Upload intent identifier
        presignedUrl:
          type: string
          description: Presigned S3/R2 PUT URL for staging upload
        stagingKey:
          type: string
          description: Temporary storage staging key
        maxByteSize:
          type: integer
          description: Maximum allowed payload size in bytes
        expiresIn:
          type: integer
          description: Presigned URL expiration time in seconds

    BuildWithAkMediaFinalizeRequest:
      type: object
      required:
        - stagingKey
        - kind
      properties:
        stagingKey:
          type: string
          description: Temporary staging key returned by upload-intent
        kind:
          type: string
          enum: [logo, cover, screenshot]
          description: Media asset kind

    BuildWithAkMediaFinalizeResponse:
      type: object
      required:
        - success
        - assetId
        - assetUrl
        - mime
        - width
        - height
      properties:
        success:
          type: boolean
        assetId:
          type: string
          format: uuid
          description: Immutable asset ID
        assetUrl:
          type: string
          description: Public CDN URL for the finalized asset
        mime:
          type: string
        width:
          type: integer
        height:
          type: integer

    BuildWithAkCategory:
      type: string
      enum:
        - developer_tools
        - ai_agents
        - saas
        - productivity
        - ecommerce
        - marketing_sales
        - education
        - other
      description: Category taxonomy for product listings

    BuildWithAkBlockHeroBanner:
      type: object
      required:
        - type
        - title
        - tagline
      properties:
        type:
          type: string
          enum: [hero_banner]
        title:
          type: string
        tagline:
          type: string
        badges:
          type: array
          items:
            type: string

    BuildWithAkBlockColumns:
      type: object
      required:
        - type
        - variant
        - items
      properties:
        type:
          type: string
          enum: [columns]
        variant:
          type: string
          enum: [two, three, bento]
        items:
          type: array
          items:
            type: object
            required:
              - heading
              - body
            properties:
              heading:
                type: string
              body:
                type: string

    BuildWithAkBlockAgentkitStory:
      type: object
      required:
        - type
        - body
        - usedKits
      properties:
        type:
          type: string
          enum: [agentkit_story]
        body:
          type: string
        usedKits:
          type: array
          items:
            type: string
            enum: [engineer, marketing, combo, app]

    BuildWithAkBlockTechStack:
      type: object
      required:
        - type
        - tags
      properties:
        type:
          type: string
          enum: [tech_stack]
        tags:
          type: array
          items:
            type: string

    BuildWithAkBlockScreenshotGallery:
      type: object
      required:
        - type
        - images
      properties:
        type:
          type: string
          enum: [screenshot_gallery]
        images:
          type: array
          items:
            type: object
            required:
              - assetId
              - alt
            properties:
              assetId:
                type: string
                format: uuid
              alt:
                type: string

    BuildWithAkBlockImageFull:
      type: object
      required:
        - type
        - assetId
        - alt
      properties:
        type:
          type: string
          enum: [image_full]
        assetId:
          type: string
          format: uuid
        alt:
          type: string
        caption:
          type: string

    BuildWithAkBlockCarouselGallery:
      type: object
      required:
        - type
        - images
      properties:
        type:
          type: string
          enum: [carousel_gallery]
        images:
          type: array
          items:
            type: object
            required:
              - assetId
              - alt
            properties:
              assetId:
                type: string
                format: uuid
              alt:
                type: string
              caption:
                type: string

    BuildWithAkBlockMakerQuote:
      type: object
      required:
        - type
        - quote
        - attribution
        - quoteSource
      properties:
        type:
          type: string
          enum: [maker_quote]
        quote:
          type: string
        attribution:
          type: string
        quoteSource:
          type: string

    BuildWithAkBlockOutboundCta:
      type: object
      required:
        - type
        - label
      properties:
        type:
          type: string
          enum: [outbound_cta]
        label:
          type: string
        note:
          type: string


    BuildWithAkBlockVideo:
      type: object
      required:
        - type
        - url
      properties:
        type:
          type: string
          enum: [video]
        url:
          type: string
          description: YouTube video URL
        title:
          type: string
        caption:
          type: string
    BuildWithAkBlockActivities:
      type: object
      required: [type]
      description: Owner-managed product updates, rendered newest date first.
      properties:
        type:
          type: string
          enum: [activities]
        title:
          type: string
          maxLength: 120
          default: Activities
        items:
          type: array
          maxItems: 50
          default: []
          items:
            type: object
            required: [title, description, date]
            properties:
              title:
                type: string
                maxLength: 120
              description:
                type: string
                maxLength: 2000
              date:
                type: string
                format: date
                description: Calendar date in YYYY-MM-DD format.
              url:
                type: string
                format: uri
                maxLength: 2000
                description: Optional public HTTPS link; credentials and private IP addresses are rejected.

    BuildWithAkBlockPulse:
      type: object
      required: [type]
      description: Recorded checks of the published main website. No custom target or client-supplied health data; previews show unknown status.
      properties:
        type:
          type: string
          enum: [pulse]
        title:
          type: string
          maxLength: 120
          default: Pulse

    BuildWithAkBlock:
      type: object
      required:
        - id
        - order
        - content
      properties:
        id:
          type: string
        order:
          type: integer
        content:
          oneOf:
            - $ref: '#/components/schemas/BuildWithAkBlockHeroBanner'
            - $ref: '#/components/schemas/BuildWithAkBlockColumns'
            - $ref: '#/components/schemas/BuildWithAkBlockAgentkitStory'
            - $ref: '#/components/schemas/BuildWithAkBlockTechStack'
            - $ref: '#/components/schemas/BuildWithAkBlockScreenshotGallery'
            - $ref: '#/components/schemas/BuildWithAkBlockImageFull'
            - $ref: '#/components/schemas/BuildWithAkBlockCarouselGallery'
            - $ref: '#/components/schemas/BuildWithAkBlockMakerQuote'
            - $ref: '#/components/schemas/BuildWithAkBlockOutboundCta'
            - $ref: '#/components/schemas/BuildWithAkBlockActivities'
            - $ref: '#/components/schemas/BuildWithAkBlockPulse'
            - $ref: '#/components/schemas/BuildWithAkBlockVideo'

    BuildWithAkUpsertListingRequest:
      type: object
      required:
        - name
        - slug
        - tagline
        - category
        - websiteUrl
        - logoAssetId
      properties:
        name:
          type: string
          description: Product name (1-64 chars)
        slug:
          type: string
          pattern: '^[a-z0-9]+(?:-[a-z0-9]+)*$'
          description: URL-safe slug (3-48 lowercase alphanumeric with hyphens)
        tagline:
          type: string
          description: Product pitch (5-120 chars)
        category:
          $ref: '#/components/schemas/BuildWithAkCategory'
        websiteUrl:
          type: string
          format: uri
          description: Canonical HTTPS website destination URL
        demoUrl:
          type: string
          format: uri
          description: Optional HTTPS product demo URL
        githubUrl:
          type: string
          format: uri
          description: Optional HTTPS GitHub repository URL
        twitterUrl:
          type: string
          format: uri
          description: Optional HTTPS Twitter/X profile or post URL
        logoAssetId:
          type: string
          format: uuid
          description: Mandatory uploaded thumbnail asset ID (kind=logo)
        coverAssetId:
          type: string
          format: uuid
          description: Optional uploaded banner cover asset ID (kind=cover)
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'
        expectedDraftRevisionId:
          type: string
          format: uuid
          description: Optional optimistic CAS locking revision ID

    BuildWithAkSaveDraftResponse:
      type: object
      required:
        - success
        - listingId
        - draftRevisionId
        - slug
        - contentHash
      properties:
        success:
          type: boolean
        listingId:
          type: string
          format: uuid
        draftRevisionId:
          type: string
          format: uuid
        slug:
          type: string
        contentHash:
          type: string

    BuildWithAkGetListingResponse:
      type: object
      properties:
        listing:
          type: object
          nullable: true
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
            slug:
              type: string
            tagline:
              type: string
            category:
              type: string
            status:
              type: string
              enum: [draft, in_review, changes_requested, approved, published, unpublished, rejected, archived]
            isFeatured:
              type: boolean
            featuredRank:
              type: integer
            upvotesCount:
              type: integer
            publishedAt:
              type: string
              format: date-time
              nullable: true
            updatedAt:
              type: string
              format: date-time
        revision:
          type: object
          nullable: true
          properties:
            id:
              type: string
              format: uuid
            metadata:
              type: object
            blocks:
              type: array
              items:
                $ref: '#/components/schemas/BuildWithAkBlock'
            contentHash:
              type: string
            createdAt:
              type: string
              format: date-time

    BuildWithAkListingQuota:
      type: object
      description: "Listing quota. limit and remaining are null when unlimited (admin)."
      required: [limit, used, remaining, freeSlots, purchasedSlots, unlimited]
      properties:
        limit:
          type: [integer, 'null']
        used:
          type: integer
        remaining:
          type: [integer, 'null']
        freeSlots:
          type: integer
        purchasedSlots:
          type: integer
        unlimited:
          type: boolean

    BuildWithAkListListingsResponse:
      type: object
      required: [listings, total, limit, offset, quota, purchaseUrl]
      properties:
        listings:
          type: array
          items:
            type: object
            required: [id, name, slug, category, status, upvotesCount, createdAt, updatedAt]
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              slug:
                type: string
              tagline:
                type: [string, 'null']
              category:
                type: string
              status:
                type: string
              upvotesCount:
                type: integer
              publishedAt:
                type: [string, 'null']
                format: date-time
              submittedAt:
                type: [string, 'null']
                format: date-time
              createdAt:
                type: string
                format: date-time
              updatedAt:
                type: string
                format: date-time
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
        quota:
          $ref: '#/components/schemas/BuildWithAkListingQuota'
        purchaseUrl:
          type: string
          format: uri

    BuildWithAkSubmitListingRequest:
      type: object
      required:
        - listingId
      properties:
        listingId:
          type: string
          format: uuid

    BuildWithAkSubmitListingResponse:
      type: object
      required:
        - success
        - listing
      properties:
        success:
          type: boolean
        listing:
          type: object

    BuildWithAkUpvoteStatusResponse:
      type: object
      required:
        - upvoted
        - upvotesCount
      properties:
        upvoted:
          type: boolean
        upvotesCount:
          type: integer

    BuildWithAkToggleUpvoteResponse:
      type: object
      required:
        - success
        - upvoted
        - upvotesCount
      properties:
        success:
          type: boolean
        upvoted:
          type: boolean
        upvotesCount:
          type: integer

    BuildWithAkViewBeaconResponse:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean

    BuildWithAkBlockContent:
      type: object
      description: Discriminated union of product showcase block content
      oneOf:
        - $ref: '#/components/schemas/BuildWithAkBlockHeroBanner'
        - $ref: '#/components/schemas/BuildWithAkBlockColumns'
        - $ref: '#/components/schemas/BuildWithAkBlockAgentkitStory'
        - $ref: '#/components/schemas/BuildWithAkBlockTechStack'
        - $ref: '#/components/schemas/BuildWithAkBlockScreenshotGallery'
        - $ref: '#/components/schemas/BuildWithAkBlockImageFull'
        - $ref: '#/components/schemas/BuildWithAkBlockCarouselGallery'
        - $ref: '#/components/schemas/BuildWithAkBlockMakerQuote'
        - $ref: '#/components/schemas/BuildWithAkBlockOutboundCta'
        - $ref: '#/components/schemas/BuildWithAkBlockActivities'
        - $ref: '#/components/schemas/BuildWithAkBlockPulse'
        - $ref: '#/components/schemas/BuildWithAkBlockVideo'

    BuildWithAkInsertBlockRequest:
      type: object
      required:
        - content
      properties:
        id:
          type: string
          description: Optional custom block ID (auto-generated if omitted)
        order:
          type: integer
          description: Optional 1-based order index
        content:
          $ref: '#/components/schemas/BuildWithAkBlockContent'

    BuildWithAkInsertBlockResponse:
      type: object
      required:
        - success
        - block
        - blocks
      properties:
        success:
          type: boolean
        block:
          $ref: '#/components/schemas/BuildWithAkBlock'
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

    BuildWithAkPatchBlockRequest:
      type: object
      properties:
        order:
          type: integer
        content:
          $ref: '#/components/schemas/BuildWithAkBlockContent'

    BuildWithAkPatchBlockResponse:
      type: object
      required:
        - success
        - block
        - blocks
      properties:
        success:
          type: boolean
        block:
          $ref: '#/components/schemas/BuildWithAkBlock'
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

    BuildWithAkGetBlocksResponse:
      type: object
      required:
        - success
        - listingId
        - draftRevisionId
        - blocks
      properties:
        success:
          type: boolean
        listingId:
          type: string
          format: uuid
        draftRevisionId:
          type: string
          format: uuid
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

    BuildWithAkUpdateBlocksRequest:
      type: object
      required:
        - blocks
      properties:
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

    BuildWithAkReorderBlocksRequest:
      type: object
      required:
        - blockIds
      properties:
        blockIds:
          type: array
          items:
            type: string
          description: Complete ordered list of block IDs

    BuildWithAkReorderBlocksResponse:
      type: object
      required:
        - success
        - blocks
      properties:
        success:
          type: boolean
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

    BuildWithAkDeleteBlockResponse:
      type: object
      required:
        - success
        - message
        - blocks
      properties:
        success:
          type: boolean
        message:
          type: string
        blocks:
          type: array
          items:
            $ref: '#/components/schemas/BuildWithAkBlock'

paths:
  # Build with AK Customer Listing & Revision Endpoints
  /build-with-ak/listing/analytics:
    get:
      tags:
        - Build with AK - Listings
      operationId: getBuildWithAkListingAnalytics
      summary: Get owned product page analytics
      description: |
        Customer API key or session required; current entitlement rechecked. Only owned listings are accessible,
        including archived/rejected listings when listingId is explicit. Omit listingId for the active listing.
        Inclusive UTC dates; default to today and from 29 days before to. Maximum 366 days. Future to, unknown
        and duplicate parameters rejected. Aggregate first-party PostgreSQL telemetry only; no visitor IDs or
        order details. Limit: 30 requests/minute per user per server process. All responses use Cache-Control:
        private, no-store.
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:read
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: An owned listing ID. Defaults to the active listing.
        - name: from
          in: query
          required: false
          schema:
            type: string
            format: date
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Inclusive UTC calendar date (YYYY-MM-DD).
        - name: to
          in: query
          required: false
          schema:
            type: string
            format: date
            pattern: ^\d{4}-\d{2}-\d{2}$
          description: Inclusive UTC calendar date (YYYY-MM-DD).
      responses:
        '200':
          description: Owned product analytics
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkAnalyticsResponse'
        '400':
          description: Invalid date range or query
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
        '401':
          description: Missing or invalid credentials
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
        '403':
          description: Customer not eligible
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
        '404':
          description: Listing missing or not owned
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
        '429':
          description: Too many requests
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
        '500':
          description: Analytics unavailable
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                  - code
                properties:
                  error:
                    type: string
                  code:
                    type: string
  /build-with-ak/listing:
    get:
      summary: Get customer product listing and active revision
      description: Fetches the authenticated customer's current product listing, draft revision, and published revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:read
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      responses:
        '200':
          description: Listing and revision fetched successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkGetListingResponse'
        '400':
          description: "Malformed listingId (INVALID_LISTING_ID) or query"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: "Listing not found or not owned"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      summary: Upsert customer draft product listing
      description: Creates or updates the customer's draft product listing and creates an immutable draft revision with copy-on-write CAS.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkUpsertListingRequest'
      responses:
        '200':
          description: Draft revision saved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkSaveDraftResponse'
        '400':
          description: "Malformed listingId (INVALID_LISTING_ID) or query"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: "Listing not found or not owned"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: "Stale revision conflict (STALE_REVISION), listing quota reached when creating the first listing (LISTING_QUOTA_EXCEEDED), or slug already taken (SLUG_TAKEN)"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation error or invalid unfinalized asset reference
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    post:
      summary: "Create a new product listing"
      description: "Creates a new draft listing for the caller within the listing quota: an AgentKit customer gets one listing, each completed Build with AK Publisher purchase adds one more, and admins are unlimited. Rejected or archived listings do not count. Same body as PUT without expectedDraftRevisionId."
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkUpsertListingRequest'
      responses:
        '201':
          description: "Listing created with its first draft revision"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkSaveDraftResponse'
        '400':
          description: "Malformed listingId (INVALID_LISTING_ID) or query"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: "Authentication required"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: "Customer verification required"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: "Listing quota reached (code LISTING_QUOTA_EXCEEDED, includes quota and purchaseUrl) or slug already taken (code SLUG_TAKEN)"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: "Validation error or invalid unfinalized asset reference"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/listings:
    get:
      operationId: listBuildWithAkListings
      summary: "List your product listings and quota"
      description: "Returns the caller's active (non-rejected, non-archived) listings oldest first, with pagination and the listing quota. Cache-Control: private, no-store."
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:read
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: "Page size (1-100, default 20)"
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: "Rows to skip (default 0)"
      responses:
        '200':
          description: "Owned listings and quota"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkListListingsResponse'
        '400':
          description: "Malformed listingId (INVALID_LISTING_ID) or query"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: "Authentication required"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: "Customer verification required"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/listing/submit:
    post:
      summary: Submit product listing for review
      description: Submits the customer's draft revision for administrator moderation and claim verification.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkSubmitListingRequest'
      responses:
        '200':
          description: Listing submitted for review successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkSubmitListingResponse'
        '400':
          description: Illegal state transition
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Listing not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid request payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  # Build with AK Public Directory & Telemetry Endpoints

  /build-with-ak/listing/blocks:
    get:
      summary: Get current draft product layout blocks
      description: Returns the full ordered array of layout blocks in the customer's active draft revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:read
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      responses:
        '200':
          description: Draft layout blocks retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkGetBlocksResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Listing or draft revision not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      summary: Replace all draft layout blocks
      description: Replaces the full ordered array of layout blocks in the draft revision and creates a new immutable revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkUpdateBlocksRequest'
      responses:
        '200':
          description: Draft layout blocks updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkGetBlocksResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid block schema or unfinalized asset reference
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Add a new block to product layout
      description: Appends or inserts a new layout block into the customer's draft revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkInsertBlockRequest'
      responses:
        '200':
          description: Block added successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkInsertBlockResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid block payload or asset reference
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/listing/blocks/{blockId}:
    patch:
      summary: Update a specific block's content or order
      description: Updates the content or display order of an existing layout block in the customer's draft revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
        - name: blockId
          in: path
          required: true
          schema:
            type: string
          description: Unique block ID to update
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkPatchBlockRequest'
      responses:
        '200':
          description: Block updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkPatchBlockResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Block not found in draft revision
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid patch payload or asset reference
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete a block from product layout
      description: Removes a layout block by ID from the customer's draft revision.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
        - name: blockId
          in: path
          required: true
          schema:
            type: string
          description: Unique block ID to delete
      responses:
        '200':
          description: Block deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkDeleteBlockResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Block not found in draft revision
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/listing/blocks/reorder:
    post:
      summary: Reorder layout blocks
      description: Reorders the layout blocks in the customer's draft revision according to the provided block IDs sequence.
      tags: [Build with AK - Listings]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      parameters:
        - name: listingId
          in: query
          required: false
          schema:
            type: string
            format: uuid
          description: "Owned active listing to target. Omit to use your oldest active listing (single-listing clients keep working)."
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkReorderBlocksRequest'
      responses:
        '200':
          description: Blocks reordered successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkReorderBlocksResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid reorder payload
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /build-with-ak/{slug}/upvote:
    get:
      summary: Get product upvote status
      description: Returns community upvote status and total count for a published product listing.
      tags: [Build with AK - Directory]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Product listing slug
        - name: x-bwak-fingerprint
          in: header
          required: false
          schema:
            type: string
          description: Optional client fingerprint for anonymous visitor upvote deduplication
      responses:
        '200':
          description: Upvote status retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkUpvoteStatusResponse'
    post:
      summary: Toggle product upvote
      description: Toggles a community upvote for a published product listing using authenticated session or anonymous fingerprint.
      tags: [Build with AK - Directory]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Product listing slug
        - name: x-bwak-fingerprint
          in: header
          required: false
          schema:
            type: string
          description: Optional client fingerprint for anonymous visitor upvote deduplication
      responses:
        '200':
          description: Upvote toggled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkToggleUpvoteResponse'
        '404':
          description: Listing not found or inactive
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/{slug}/visit:
    get:
      summary: Outbound website referral redirect
      description: Records an outbound click telemetry event and redirects the visitor to the product's external website with standard UTM attribution.
      tags: [Build with AK - Directory]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Product listing slug
      responses:
        '307':
          description: Temporary redirect to external product website with UTM attribution
        '308':
          description: Permanent redirect to canonical product slug
        '400':
          description: Invalid destination website URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Product listing not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/{slug}/view:
    post:
      summary: Record product view beacon
      description: Records a deduplicated page view impression telemetry event for the published product showcase.
      tags: [Build with AK - Directory]
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
          description: Product listing slug
      responses:
        '200':
          description: View beacon recorded successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkViewBeaconResponse'
        '404':
          description: Product listing not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  # Build with AK Media Endpoints
  /build-with-ak/media/upload-intent:
    post:
      summary: Authorize one-time media upload intent
      description: Authorizes a presigned staging upload URL with size limits and anti-replay intent tracking.
      tags: [Build with AK - Media]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkUploadIntentRequest'
      responses:
        '200':
          description: Upload intent generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkUploadIntentResponse'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Customer verification required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Invalid payload or unsupported MIME type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Storage service unconfigured or server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /build-with-ak/media/finalize:
    post:
      summary: Finalize and verify uploaded media asset
      description: Consumes the upload intent atomically, validates magic-bytes/dimensions, and writes immutable asset record.
      tags: [Build with AK - Media]
      security:
        - ApiKeyAuth: []
        - CookieAuth: []
        - BuildWithAkDelegatedAuth: []
      x-required-oauth-scope: build-with-ak:write
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BuildWithAkMediaFinalizeRequest'
      responses:
        '200':
          description: Media asset verified and finalized successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildWithAkMediaFinalizeResponse'
        '400':
          description: Invalid, expired, or already consumed upload intent
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Authentication required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Staging key ownership mismatch or unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Staging file not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Concurrent race condition or already finalized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: File size exceeds allowed limit
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Structural decode or image dimension validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal database or storage error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  # AgentKit Feedback
  /agentkit/feedback:
    post:
      summary: Submit AgentKit client feedback
      description: |
        Accept feedback from authenticated AgentKit clients, re-redact the submitted
        preview and fields, rate limit by account or license, and create a GitHub
        issue through the server-owned integration.
      tags: [AgentKit Feedback]
      security:
        - ApiKeyAuth: []
        - BearerAuth: []
        - CookieAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FeedbackRequest'
      responses:
        '200':
          description: Feedback issue created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackResponse'
        '400':
          description: Invalid schema, validation, or size failure
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackError'
        '401':
          description: Missing, expired, or unsupported token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackError'
        '429':
          description: Feedback rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: string
              description: Seconds until the client should retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackError'
        '502':
          description: Transient GitHub/upstream failure
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackError'
        '503':
          description: Endpoint disabled or GitHub integration unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeedbackError'

  # Referrals
  /referrals/referees:
    get:
      summary: List referred conversion rows
      description: |
        Return the current authenticated user's referral conversion rows with commission status,
        display-only order fields, and minimal referee profile summary. Each row represents one
        commission/conversion, not a deduplicated person.
      tags: [Referrals]
      security:
        - ApiKeyAuth: []
      parameters:
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum: [all, pending, approved, paid, cancelled]
            default: all
          description: Filter by commission status.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: Page size.
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            maximum: 5000
            default: 0
          description: Offset into the current filtered result set.
        - name: orderRef
          in: query
          required: false
          schema:
            type: string
            minLength: 8
            maxLength: 8
            pattern: '^[0-9a-fA-F]{8}$'
          description: Exact match on order display id, for example `ff95c7f6` from `order.displayId`.
        - name: sort
          in: query
          required: false
          schema:
            type: string
            enum: [createdAt, amount, status]
            default: createdAt
          description: Sort column.
        - name: order
          in: query
          required: false
          schema:
            type: string
            enum: [asc, desc]
            default: desc
          description: Sort direction.
      responses:
        '200':
          description: Owner-scoped referral conversion rows
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReferralRefereesResponse'
              examples:
                default:
                  value:
                    data:
                      - commissionId: "11111111-1111-4111-8111-111111111111"
                        status: pending
                        amount: 990
                        currency: USD
                        createdAt: "2026-05-01T00:00:00.000Z"
                        approvedAt: null
                        paidAt: null
                        order:
                          displayId: "ff95c7f6"
                          productType: engineer_kit
                          status: completed
                        referee:
                          name: Buyer
                          avatarUrl: null
                          emailMasked: "b****@example.com"
                    pagination:
                      limit: 20
                      offset: 0
                      total: 1
                      hasMore: false
                    filters:
                      status: all
                      sort: createdAt
                      order: desc
                      orderRef: ff95c7f6
        '400':
          description: Invalid query parameter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: User is not eligible for referral data
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Error'
                  - type: object
                    properties:
                      eligible:
                        type: boolean
                        const: false
        '429':
          description: Rate limited
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Server error or insecure session configuration
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  # API Key Management
  /keys:
    get:
      summary: List API keys
      description: Get all API keys for the authenticated user
      tags: [API Keys]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: List of API keys
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      $ref: '#/components/schemas/ApiKey'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create API key
      description: Create a new API key. The full key is only shown once.
      tags: [API Keys]
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiKeyCreate'
      responses:
        '201':
          description: API key created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreated'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: License required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /keys/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    get:
      summary: Get API key details
      tags: [API Keys]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: API key details
          content:
            application/json:
              schema:
                type: object
                properties:
                  key:
                    $ref: '#/components/schemas/ApiKey'
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete API key
      description: Soft delete (deactivate) an API key
      tags: [API Keys]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Key deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /keys/{id}/rotate:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    post:
      summary: Rotate API key
      description: Generate a new key value with optional grace period for old key
      tags: [API Keys]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Key rotated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreated'
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /keys/{id}/revoke:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    post:
      summary: Revoke API key
      description: Immediately invalidate an API key
      tags: [API Keys]
      security:
        - BearerAuth: []
      responses:
        '200':
          description: Key revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /keys/{id}/usage:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
    get:
      summary: Get API key usage stats
      description: Get usage statistics from ClickHouse and current rate limit info
      tags: [API Keys]
      security:
        - BearerAuth: []
      parameters:
        - name: days
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 30
            default: 7
          description: Number of days for usage stats (1-30)
      responses:
        '200':
          description: Usage statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  totalRequests:
                    type: integer
                  successfulRequests:
                    type: integer
                  failedRequests:
                    type: integer
                  avgResponseTime:
                    type: number
                  totalUsageCount:
                    type: integer
                    description: Lifetime usage count
                  rateLimit:
                    type: object
                    properties:
                      limit:
                        type: integer
                      used:
                        type: integer
                      remaining:
                        type: integer
                      windowHours:
                        type: integer
        '404':
          description: Key not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /keys/validate:
    post:
      summary: Validate API key
      description: Check if an API key is valid and return metadata
      tags: [API Keys]
      security:
        - ApiKeyAuth: []
      responses:
        '200':
          description: Key is valid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationResult'
        '400':
          description: API key required
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  # VidCap Health & Models
  /proxy/vidcap/v1/healthz:
    get:
      summary: VidCap health check
      description: Check VidCap service health status
      tags: [VidCap - Health]
      responses:
        '200':
          description: Service healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthCheck'

  /proxy/vidcap/v1/ai/models:
    get:
      summary: List AI models
      description: Get available AI models for summary and article generation
      tags: [VidCap - Health]
      responses:
        '200':
          description: List of models
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AIModels'

  # VidCap Video
  /proxy/vidcap/v1/video/{videoId}:
    parameters:
      - name: videoId
        in: path
        required: true
        schema:
          type: string
        description: Video ID from VidCap
    get:
      summary: Get video by ID
      description: Retrieve processed video by VidCap video ID
      tags: [VidCap - Video]
      responses:
        '200':
          description: Video data
          content:
            application/json:
              schema:
                type: object
        '404':
          description: Video not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  # VidCap YouTube Operations
  /proxy/vidcap/v1/youtube/info:
    get:
      summary: Get YouTube video info
      description: Retrieve metadata for a YouTube video
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
      responses:
        '200':
          description: Video info
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeInfo'
        '400':
          description: Invalid URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /proxy/vidcap/v1/youtube/media:
    get:
      summary: Get available media formats
      description: List available download formats for a YouTube video
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
      responses:
        '200':
          description: Available formats
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeMedia'

  /proxy/vidcap/v1/youtube/download:
    get:
      summary: Download video
      description: Download YouTube video in specified format
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: itag
          in: query
          schema:
            type: integer
          description: Format itag (from media endpoint)
        - name: quality
          in: query
          schema:
            type: string
            enum: [highest, lowest, audio]
          description: Quality preset
      responses:
        '200':
          description: Video stream or download URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  downloadUrl:
                    type: string
                    format: uri

  /proxy/vidcap/v1/youtube/caption:
    get:
      summary: Get video captions
      description: Extract captions/subtitles from a YouTube video
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: lang
          in: query
          schema:
            type: string
            default: en
          description: Caption language code
      responses:
        '200':
          description: Video captions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeCaption'

  /proxy/vidcap/v1/youtube/summary:
    get:
      summary: AI video summary
      description: Generate AI-powered summary of a YouTube video
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: model
          in: query
          schema:
            type: string
          description: AI model to use (from /ai/models)
      responses:
        '200':
          description: Video summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeSummary'

  /proxy/vidcap/v1/youtube/summary-custom:
    post:
      summary: Custom AI summary
      description: Generate summary with custom prompt
      tags: [VidCap - YouTube]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: YouTube video URL
                prompt:
                  type: string
                  description: Custom prompt for summary
                model:
                  type: string
                  description: AI model to use
              required:
                - url
                - prompt
      responses:
        '200':
          description: Custom summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeSummary'

  /proxy/vidcap/v1/youtube/article:
    get:
      summary: Convert to article
      description: Convert YouTube video to written article format
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: model
          in: query
          schema:
            type: string
          description: AI model to use
      responses:
        '200':
          description: Article content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeArticle'

  /proxy/vidcap/v1/youtube/screenshot:
    get:
      summary: Take screenshot
      description: Capture screenshot at specified timestamp
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: timestamp
          in: query
          schema:
            type: number
          description: Timestamp in seconds
      responses:
        '200':
          description: Screenshot URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeScreenshot'

  /proxy/vidcap/v1/youtube/screenshot-multiple:
    get:
      summary: Take multiple screenshots
      description: Capture screenshots at multiple timestamps
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: timestamps
          in: query
          schema:
            type: string
          description: Comma-separated timestamps in seconds
        - name: count
          in: query
          schema:
            type: integer
          description: Number of evenly-spaced screenshots
      responses:
        '200':
          description: Screenshot URLs
          content:
            application/json:
              schema:
                type: object
                properties:
                  screenshots:
                    type: array
                    items:
                      $ref: '#/components/schemas/YouTubeScreenshot'

  /proxy/vidcap/v1/youtube/comments:
    get:
      summary: Get video comments
      description: Retrieve comments from a YouTube video
      tags: [VidCap - YouTube]
      parameters:
        - name: url
          in: query
          required: true
          schema:
            type: string
          description: YouTube video URL
        - name: pageToken
          in: query
          schema:
            type: string
          description: Pagination token
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
          description: Number of comments to return
      responses:
        '200':
          description: Video comments
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeComments'

  /proxy/vidcap/v1/youtube/search:
    get:
      summary: Search YouTube videos
      description: Search for YouTube videos
      tags: [VidCap - YouTube]
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
          description: Search query
        - name: pageToken
          in: query
          schema:
            type: string
          description: Pagination token
        - name: limit
          in: query
          schema:
            type: integer
            default: 10
          description: Number of results
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/YouTubeSearchResult'

  # ReviewWeb - Health & Profile
  /proxy/reviewweb/v1/healthz:
    get:
      summary: Health check
      description: Check ReviewWeb service health
      tags: [ReviewWeb - Health]
      responses:
        '200':
          description: Service is healthy

  /proxy/reviewweb/v1/profile:
    get:
      summary: Get profile
      description: Get account profile and credits
      tags: [ReviewWeb - Health]
      responses:
        '200':
          description: Profile info
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewWebProfile'

  # ReviewWeb - Screenshots
  /proxy/reviewweb/v1/screenshot:
    post:
      summary: Take screenshot
      description: Capture webpage screenshot
      tags: [ReviewWeb - Screenshots]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
                width:
                  type: integer
                  default: 1280
                height:
                  type: integer
                  default: 720
              required: [url]
      responses:
        '200':
          description: Screenshot result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewWebScreenshot'

  /proxy/reviewweb/v1/screenshot/{id}:
    get:
      summary: Get screenshot
      description: Get screenshot by ID
      tags: [ReviewWeb - Screenshots]
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Screenshot details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewWebScreenshot'

  # ReviewWeb - Reviews
  /proxy/reviewweb/v1/review:
    post:
      summary: Create review
      description: Create website review
      tags: [ReviewWeb - Reviews]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Review created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewWebReview'

  /proxy/reviewweb/v1/review/{reviewId}:
    get:
      summary: Get review
      description: Get review by ID
      tags: [ReviewWeb - Reviews]
      parameters:
        - name: reviewId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Review details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReviewWebReview'

  # ReviewWeb - Scraping
  /proxy/reviewweb/v1/scrape:
    post:
      summary: Scrape URL
      description: Scrape single URL content
      tags: [ReviewWeb - Scraping]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Scraped content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScrapeResult'

  /proxy/reviewweb/v1/scrape/urls:
    post:
      summary: Scrape multiple URLs
      description: Scrape multiple URLs in batch
      tags: [ReviewWeb - Scraping]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                urls:
                  type: array
                  items:
                    type: string
                    format: uri
              required: [urls]
      responses:
        '200':
          description: Scraped results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ScrapeResult'

  /proxy/reviewweb/v1/scrape/links-map:
    post:
      summary: Get links map
      description: Extract all links from page
      tags: [ReviewWeb - Scraping]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Links map
          content:
            application/json:
              schema:
                type: object
                properties:
                  internal:
                    type: array
                    items:
                      type: string
                  external:
                    type: array
                    items:
                      type: string

  # ReviewWeb - Extraction
  /proxy/reviewweb/v1/extract:
    post:
      summary: Extract content
      description: Extract main content from URL
      tags: [ReviewWeb - Extraction]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Extracted content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExtractResult'

  /proxy/reviewweb/v1/extract/urls:
    post:
      summary: Extract from multiple URLs
      description: Extract content from multiple URLs
      tags: [ReviewWeb - Extraction]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                urls:
                  type: array
                  items:
                    type: string
                    format: uri
              required: [urls]
      responses:
        '200':
          description: Extracted results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ExtractResult'

  # ReviewWeb - Conversion
  /proxy/reviewweb/v1/convert/markdown:
    post:
      summary: Convert to markdown
      description: Convert URL to markdown format
      tags: [ReviewWeb - Conversion]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Markdown content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MarkdownResult'

  /proxy/reviewweb/v1/convert/markdown/urls:
    post:
      summary: Convert multiple to markdown
      description: Convert multiple URLs to markdown
      tags: [ReviewWeb - Conversion]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                urls:
                  type: array
                  items:
                    type: string
                    format: uri
              required: [urls]
      responses:
        '200':
          description: Markdown results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/MarkdownResult'

  # ReviewWeb - Summarization
  /proxy/reviewweb/v1/summarize/url:
    post:
      summary: Summarize URL
      description: AI-powered URL summarization
      tags: [ReviewWeb - Summarization]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Summary result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SummarizeResult'

  /proxy/reviewweb/v1/summarize/website:
    post:
      summary: Summarize website
      description: Summarize entire website
      tags: [ReviewWeb - Summarization]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Website summary
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SummarizeResult'

  /proxy/reviewweb/v1/summarize/urls:
    post:
      summary: Summarize multiple URLs
      description: Summarize multiple URLs
      tags: [ReviewWeb - Summarization]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                urls:
                  type: array
                  items:
                    type: string
                    format: uri
              required: [urls]
      responses:
        '200':
          description: Summary results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SummarizeResult'

  # ReviewWeb - URL Utilities
  /proxy/reviewweb/v1/url/is-alive:
    post:
      summary: Check URL alive
      description: Check if URL is accessible
      tags: [ReviewWeb - Health]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: URL check result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UrlCheckResult'

  /proxy/reviewweb/v1/url/get-url-after-redirects:
    post:
      summary: Get final URL
      description: Get URL after following redirects
      tags: [ReviewWeb - Health]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
              required: [url]
      responses:
        '200':
          description: Final URL
          content:
            application/json:
              schema:
                type: object
                properties:
                  originalUrl:
                    type: string
                  finalUrl:
                    type: string
                  redirectCount:
                    type: integer

  # ReviewWeb - SEO Insights
  /proxy/reviewweb/v1/seo-insights/backlinks:
    post:
      summary: Analyze backlinks
      description: Get backlink analysis for domain
      tags: [ReviewWeb - SEO]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                domain:
                  type: string
              required: [domain]
      responses:
        '200':
          description: Backlinks analysis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SeoBacklinks'

  /proxy/reviewweb/v1/seo-insights/keyword-ideas:
    post:
      summary: Generate keyword ideas
      description: Get keyword suggestions
      tags: [ReviewWeb - SEO]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                keyword:
                  type: string
              required: [keyword]
      responses:
        '200':
          description: Keyword ideas
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SeoKeywordIdeas'

  /proxy/reviewweb/v1/seo-insights/keyword-difficulty:
    post:
      summary: Check keyword difficulty
      description: Analyze keyword competition
      tags: [ReviewWeb - SEO]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                keyword:
                  type: string
              required: [keyword]
      responses:
        '200':
          description: Difficulty analysis
          content:
            application/json:
              schema:
                type: object
                properties:
                  keyword:
                    type: string
                  difficulty:
                    type: number
                  searchVolume:
                    type: integer

  /proxy/reviewweb/v1/seo-insights/traffic:
    post:
      summary: Analyze traffic
      description: Get traffic estimates for domain
      tags: [ReviewWeb - SEO]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                domainOrUrl:
                  type: string
                  description: Domain or full URL to analyze
                mode:
                  type: string
                  enum: [subdomains, exact]
                country:
                  type: string
              required: [domainOrUrl]
      responses:
        '200':
          description: Traffic analysis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SeoTraffic'
