# Fabler Labs — machine store (x402) OpenAPI 3.1 contract
#
# This document is the formal API contract for https://x402.fablerlabs.com — the
# machine-payable side of Fabler Labs, where an autonomous AI agent pays per call
# in USDC over the x402 standard (https://www.x402.org). Payment IS the auth:
# there is no account and no API key. An unpaid request to a paid endpoint returns
# HTTP 402 Payment Required with the price and on-chain payment details; the caller
# settles the USDC and replays the request with an `X-PAYMENT` header to get the
# result.
#
# Source of truth for live status and prices is always /products.json. The
# machine store is in preview — endpoints roll out as they are deployed.
#
# `x-pricing` (top level) is a machine-readable price registry in USD, kept in
# lockstep with /products.json by site/test/products-json.test.mjs.
openapi: 3.1.0

info:
  title: Fabler Labs machine store (x402 API)
  version: "2026-07-07"
  summary: A machine-payable HTTP API for AI agents, priced per call in USDC over x402.
  description: >-
    Machine-payable endpoints for AI agents. Unpaid requests to a paid endpoint
    return `402 Payment Required` with a typed challenge (price, network, asset,
    pay-to address); pay the USDC and replay with an `X-PAYMENT` header to get the
    result. Built and operated by an autonomous AI agent, filmed for transparency.
    Live status and prices are authoritative in https://fablerlabs.com/products.json.
  contact:
    name: Fabler Labs support
    email: support@fablerlabs.com
    url: https://fablerlabs.com/contact.html
  termsOfService: https://fablerlabs.com/terms.html
  license:
    name: Proprietary — usage governed by the Terms of Service
    url: https://fablerlabs.com/terms.html

servers:
  - url: https://x402.fablerlabs.com
    description: Production machine store (preview)

externalDocs:
  description: Human-readable overview of the machine store
  url: https://fablerlabs.com/x402

# Machine-readable USD price registry. Micro-endpoints are priced per successful
# call; buy-* SKUs are priced at parity with the human Stripe checkout.
x-pricing:
  scan-secrets: 0.005
  render-og: 0.01
  audit-agent-config: 0.05
  buy-pack: 24
  buy-agent-kit: 29
  buy-ai-coding-security-pack-v1: 29
  buy-constitution-packs-v1: 19

tags:
  - name: discovery
    description: Free, unpaid endpoints for capability and price discovery.
  - name: tools
    description: Paid per-call utility endpoints for AI agents.
  - name: commerce
    description: Paid autonomous purchase of product SKUs, priced at Stripe parity.

paths:
  /:
    get:
      tags: [discovery]
      operationId: getServiceDirectory
      summary: Service discovery (free)
      description: >-
        Returns a machine-readable directory of the machine store — protocol,
        settlement asset, base URL, and the list of endpoints with their prices.
        Free and unauthenticated; mirrors the `api` block of /products.json.
      security: []
      responses:
        "200":
          description: The service directory.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceDirectory"

  /scan/secrets:
    post:
      tags: [tools]
      operationId: scanSecrets
      summary: Scan text for leaked secrets (paid)
      description: >-
        Scan a code snippet or file for leaked secrets and credentials. Returns
        structured findings (rule, masked match, line, severity, fix hint).
        Priced per successful call.
      x-402:
        priceUsd: 0.005
        network: base
        asset: USDC
      x-payment-info:
        price: "$0.005"
        currency: USDC
        protocols: [x402]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ScanSecretsRequest"
      responses:
        "200":
          description: Scan complete.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ScanResult"
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "400":
          $ref: "#/components/responses/BadRequest"

  /render/og:
    post:
      tags: [tools]
      operationId: renderOg
      summary: Render a branded Open Graph image (paid)
      description: >-
        Render a branded Open Graph image (1200x630 PNG) from a title and optional
        subtitle. Returns the PNG bytes. Priced per successful call.
      x-402:
        priceUsd: 0.01
        network: base
        asset: USDC
      x-payment-info:
        price: "$0.01"
        currency: USDC
        protocols: [x402]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RenderOgRequest"
      responses:
        "200":
          description: >-
            The rendered card. Normally a 1200x630 PNG; if the PNG rasterizer
            fails to initialize on the server, the same card is served as SVG
            with Content-Type image/svg+xml.
          content:
            image/png:
              schema:
                type: string
                format: binary
            image/svg+xml:
              schema:
                type: string
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "400":
          $ref: "#/components/responses/BadRequest"

  /audit/agent-config:
    post:
      tags: [tools]
      operationId: auditAgentConfig
      summary: Audit an agent config file (paid)
      description: >-
        Audit a CLAUDE.md / AGENTS.md / agent config against current best practices.
        Returns a 0-100 score with specific, prioritized fixes. Priced per call.
      x-402:
        priceUsd: 0.05
        network: base
        asset: USDC
      x-payment-info:
        price: "$0.05"
        currency: USDC
        protocols: [x402]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AuditRequest"
      responses:
        "200":
          description: Audit complete.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditResult"
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "400":
          $ref: "#/components/responses/BadRequest"

  # Each purchasable SKU is a concrete path (not a templated /buy/{sku}) so x402
  # indexers that enumerate openapi paths can probe and price every product
  # individually — the routing in src/index.ts registers them per-slug anyway.
  /buy/pack:
    get:
      tags: [commerce]
      operationId: buyPack
      summary: Buy the AI Coding Workflow Pack ($24, zip)
      description: >-
        Buy the AI Coding Workflow Pack with USDC, at parity with the human Stripe
        checkout. On settlement, the response body is the product .zip itself
        (Content-Disposition attachment).
      x-402:
        priceUsd: 24
        network: base
        asset: USDC
      x-payment-info:
        price: "$24.00"
        currency: USDC
        protocols: [x402]
      responses:
        "200":
          description: Payment settled; the product .zip bytes.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "402":
          $ref: "#/components/responses/PaymentRequired"
  /buy/agent-kit:
    get:
      tags: [commerce]
      operationId: buyAgentKit
      summary: Buy the Autonomous Agent Starter Kit ($29, zip)
      description: >-
        Buy the Autonomous Agent Starter Kit with USDC, at parity with the human
        Stripe checkout. On settlement, the response body is the product .zip itself
        (Content-Disposition attachment).
      x-402:
        priceUsd: 29
        network: base
        asset: USDC
      x-payment-info:
        price: "$29.00"
        currency: USDC
        protocols: [x402]
      responses:
        "200":
          description: Payment settled; the product .zip bytes.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "402":
          $ref: "#/components/responses/PaymentRequired"
  /buy/ai-coding-security-pack-v1:
    get:
      tags: [commerce]
      operationId: buySecurityPack
      summary: Buy the AI Coding Security Pack ($29, zip)
      description: >-
        Buy the AI Coding Security Pack with USDC, at parity with the human Stripe
        checkout. On settlement, the response body is the product .zip itself
        (Content-Disposition attachment).
      x-402:
        priceUsd: 29
        network: base
        asset: USDC
      x-payment-info:
        price: "$29.00"
        currency: USDC
        protocols: [x402]
      responses:
        "200":
          description: Payment settled; the product .zip bytes.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "402":
          $ref: "#/components/responses/PaymentRequired"
  /buy/constitution-packs-v1:
    get:
      tags: [commerce]
      operationId: buyConstitutionPack
      summary: Buy the Agent Constitution Pack ($19, zip)
      description: >-
        Buy the Agent Constitution Pack with USDC, at parity with the human Stripe
        checkout. On settlement, the response body is the product .zip itself
        (Content-Disposition attachment).
      x-402:
        priceUsd: 19
        network: base
        asset: USDC
      x-payment-info:
        price: "$19.00"
        currency: USDC
        protocols: [x402]
      responses:
        "200":
          description: Payment settled; the product .zip bytes.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "402":
          $ref: "#/components/responses/PaymentRequired"

components:
  securitySchemes:
    x402Payment:
      type: apiKey
      in: header
      name: X-PAYMENT
      description: >-
        Base64-encoded x402 payment payload proving USDC settlement for the
        request. Obtain the required amount and pay-to address from the 402
        challenge, settle on-chain, then send the proof in this header on replay.

  responses:
    PaymentRequired:
      description: >-
        Payment required. The body is a typed x402 challenge listing the accepted
        payment terms (price, network, asset, pay-to address). Pay the USDC and
        replay the request with an `X-PAYMENT` header.
      headers:
        Accept-Payment:
          description: Signals x402 payment support.
          schema:
            type: string
            examples: ["x402"]
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/PaymentRequired"
          examples:
            auditChallenge:
              summary: 402 challenge for /audit/agent-config
              value:
                x402Version: 1
                error: payment required
                accepts:
                  - scheme: exact
                    network: base
                    asset: USDC
                    maxAmountRequired: "0.05"
                    payTo: "0x0000000000000000000000000000000000000000"
                    resource: https://x402.fablerlabs.com/audit/agent-config
                    description: Audit an agent config file; 0-100 score plus fixes.
                    maxTimeoutSeconds: 120
            scanChallenge:
              summary: 402 challenge for /scan/secrets
              value:
                x402Version: 1
                error: payment required
                accepts:
                  - scheme: exact
                    network: base
                    asset: USDC
                    maxAmountRequired: "0.005"
                    payTo: "0x0000000000000000000000000000000000000000"
                    resource: https://x402.fablerlabs.com/scan/secrets
                    description: Scan text for leaked secrets.
                    maxTimeoutSeconds: 120
            renderChallenge:
              summary: 402 challenge for /render/og
              value:
                x402Version: 1
                error: payment required
                accepts:
                  - scheme: exact
                    network: base
                    asset: USDC
                    maxAmountRequired: "0.01"
                    payTo: "0x0000000000000000000000000000000000000000"
                    resource: https://x402.fablerlabs.com/render/og
                    description: Render a branded Open Graph image.
                    maxTimeoutSeconds: 120
            buyChallenge:
              summary: 402 challenge for /buy/agent-kit
              value:
                x402Version: 1
                error: payment required
                accepts:
                  - scheme: exact
                    network: base
                    asset: USDC
                    maxAmountRequired: "29.00"
                    payTo: "0x0000000000000000000000000000000000000000"
                    resource: https://x402.fablerlabs.com/buy/agent-kit
                    description: Autonomous purchase of the Autonomous Agent Starter Kit.
                    maxTimeoutSeconds: 300

    BadRequest:
      description: Malformed request body.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"

  schemas:
    ServiceDirectory:
      type: object
      description: Machine-readable directory of the machine store.
      required: [protocol, base_url, settlement, endpoints]
      properties:
        brand:
          type: string
          examples: ["Fabler Labs"]
        protocol:
          type: string
          examples: ["x402"]
        spec:
          type: string
          format: uri
          examples: ["https://www.x402.org"]
        base_url:
          type: string
          format: uri
          examples: ["https://x402.fablerlabs.com"]
        settlement:
          type: string
          examples: ["USDC"]
        status:
          type: string
          examples: ["preview"]
        service_desc:
          type: string
          format: uri
          description: URL of this OpenAPI document.
          examples: ["https://fablerlabs.com/x402/openapi.yaml"]
        endpoints:
          type: array
          items:
            $ref: "#/components/schemas/EndpointInfo"

    EndpointInfo:
      type: object
      required: [id, path, method, price_usd]
      properties:
        id:
          type: string
        path:
          type: string
          examples: ["/scan/secrets"]
        method:
          type: string
          examples: ["POST"]
        price_usd:
          description: Price in USD; a number for fixed-price endpoints or a note for parity pricing.
          oneOf:
            - type: number
            - type: string
        description:
          type: string
        url:
          type: string
          format: uri

    PaymentRequired:
      type: object
      description: A typed x402 payment challenge.
      required: [x402Version, accepts]
      properties:
        x402Version:
          type: integer
          examples: [1]
        error:
          type: string
          examples: ["payment required"]
        accepts:
          type: array
          minItems: 1
          items:
            $ref: "#/components/schemas/PaymentRequirement"

    PaymentRequirement:
      type: object
      description: One acceptable way to pay for the resource.
      required: [scheme, network, asset, maxAmountRequired, payTo, resource]
      properties:
        scheme:
          type: string
          examples: ["exact"]
        network:
          type: string
          examples: ["base"]
        asset:
          type: string
          examples: ["USDC"]
        maxAmountRequired:
          type: string
          description: Maximum amount to pay, as a decimal string in the asset's units.
          examples: ["0.05"]
        payTo:
          type: string
          description: On-chain address that must receive the payment.
          examples: ["0x0000000000000000000000000000000000000000"]
        resource:
          type: string
          format: uri
          description: The resource being paid for.
        description:
          type: string
        maxTimeoutSeconds:
          type: integer
          description: How long the challenge remains valid.
          examples: [120]

    ScanSecretsRequest:
      type: object
      description: Text to scan for leaked secrets.
      required: [text]
      properties:
        text:
          type: string
          description: The text to scan.

    ScanResult:
      type: object
      required: [findings, clean]
      properties:
        findings:
          type: array
          items:
            $ref: "#/components/schemas/ScanFinding"
        clean:
          type: boolean
          description: true when no findings were produced.

    ScanFinding:
      type: object
      required: [rule, match_masked, line, severity, fix_hint]
      properties:
        rule:
          type: string
          description: Name of the detection rule that fired.
          examples: ["aws access key id"]
        match_masked:
          type: string
          description: The matched substring, masked (first 4 chars + "***") — never the full secret.
          examples: ["AKIA***"]
        line:
          type: integer
          description: 1-indexed line number within the scanned text.
          examples: [12]
        severity:
          type: string
          enum: [low, medium, high, critical]
        fix_hint:
          type: string
          description: Short, actionable remediation hint for this rule.

    RenderOgRequest:
      type: object
      required: [title]
      properties:
        title:
          type: string
        subtitle:
          type: string
        theme:
          type: string
          enum: [dark, light]
          default: dark

    AuditRequest:
      type: object
      description: An agent config file to audit.
      required: [content, kind]
      properties:
        content:
          type: string
          description: Raw text of the document to audit.
        kind:
          type: string
          description: Which rubric to apply ("CLAUDE.md" and "claude-md" are equivalent).
          enum: ["CLAUDE.md", "claude-md", "constitution"]
          examples: ["CLAUDE.md"]

    AuditResult:
      type: object
      required: [score, findings, summary]
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
        findings:
          type: array
          description: One finding per rubric rule, ordered worst-first (fail, warn, pass).
          items:
            $ref: "#/components/schemas/AuditFinding"
        summary:
          type: string
          description: One-line plain-language summary of the score and top gaps.

    AuditFinding:
      type: object
      required: [rule, label, severity, excerpt, fix, weight]
      properties:
        rule:
          type: string
          description: Stable rule id.
          examples: ["data-not-instructions"]
        label:
          type: string
          description: Human-readable rule name.
        severity:
          type: string
          enum: [pass, warn, fail]
        excerpt:
          type: string
          description: The offending line lifted from the document, or "" when none applies.
        fix:
          type: string
          description: Concrete, ready-to-apply guidance (positive confirmation on pass).
        weight:
          type: integer
          description: Max points this rule contributes to the score.

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: string
        detail:
          type: string

security:
  - x402Payment: []
