openapi: 3.1.0
info:
  title: PageVerified Gateway API
  version: 0.5.0
  summary: Verified AI-agent directory, evidence capture, commerce, fulfilment, and mock-credit gateway endpoints for PageVerified.
  description: >
    PageVerified exposes agent-readable discovery files, paid-offer pricing,
    mock-credit gateway calls, receipts, and fulfilment intake surfaces. Live
    autonomous money movement is not enabled; Stripe checkout links are used for
    human/self-serve purchases while agent payment rails remain under validation.
    API endpoints of retired products (trust pages, Vendor Pack, NDIS
    Audit-Ready, PageVerified Tenders and PageVerified Studio) are not listed here and
    answer 410 {"error":"retired"}.
servers:
  - url: https://pageverified.com
  - url: https://agentstack-gateway.vercel.app
  - url: /
paths:
  /health:
    get:
      summary: Deployment health
      operationId: getHealth
      responses:
        "200":
          description: Runtime health and live-money boundary.
          content:
            application/json:
              schema:
                type: object
                required: [status, service, live_money_movement, ledger]
                properties:
                  status: { type: string }
                  service: { type: string }
                  live_money_movement: { type: boolean }
                  ledger: { type: string }
  /.well-known/attest.json:
    get:
      summary: PageVerified service index
      operationId: getAttestIndex
      responses:
        "200":
          description: Service index
          content:
            application/json:
              schema:
                $ref: ./schemas/agentstack-service-index.v0.schema.json
  /api/tools.json:
    get:
      summary: Complete verified AI-agent tool index
      operationId: listVerifiedAgentTools
      responses:
        "200":
          description: Public verified tool records, categories and scoped check evidence.
          content:
            application/json:
              schema:
                type: object
                required: [name, canonical_url, generated_at, verification_scope, count, categories, tools]
                properties:
                  name: { type: string }
                  canonical_url: { type: string, format: uri }
                  generated_at: { type: string, format: date-time }
                  verification_scope: { type: string }
                  count: { type: integer, minimum: 0 }
                  categories: { type: array, items: { type: object } }
                  tools: { type: array, items: { type: object } }
  /api/directory-submit:
    post:
      summary: Submit and verify a public AI-agent tool
      operationId: submitDirectoryTool
      description: Persists the submission as queued, then runs the same scoped verifier used by seed ingestion. Verified listings publish immediately; ambiguous evidence is held for manual review.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, url, tagline, description, category, pricing_model, public_information]
              properties:
                name: { type: string, minLength: 2, maxLength: 100 }
                url: { type: string, format: uri }
                tagline: { type: string, minLength: 6, maxLength: 180 }
                description: { type: string, minLength: 10, maxLength: 2000 }
                category: { type: string, enum: [mcp-servers, agent-frameworks, browser-automation, memory-rag, evals, voice, coding-agents, workflow-orchestration, apis-for-agents, misc-dev-tools] }
                pricing_model: { type: string, enum: [free, freemium, paid, open-source, contact] }
                maker: { type: string, maxLength: 120 }
                maker_contact: { type: string, format: email, maxLength: 254 }
                github: { type: string, format: uri }
                public_information: { type: string, const: confirmed }
      responses:
        "200": { description: The verified URL already exists and its public listing is returned. }
        "201": { description: "Submission persisted, verified and published." }
        "202": { description: Submission persisted for manual review or recorded as rejected. }
        "400": { description: Invalid fields or declaration. }
        "429": { description: Hourly IP rate limit exceeded. }
        "503": { description: Durable directory store unavailable. }
  /api/v1/keys:
    post:
      summary: Issue an email-free PageVerified Capture API key
      operationId: issueCaptureKey
      description: Returns the bearer key once with 25 free credits. Limited to three keys per source IP in a rolling 24-hour window.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [label]
              properties:
                label: { type: string, minLength: 1, maxLength: 80 }
      responses:
        "201": { description: Key issued once with its remaining credit balance. }
        "400": { description: Invalid label. }
        "429": { description: Free-key issuance limit reached. }
        "503": { description: Durable Capture store unavailable. }
  /api/v1/keys/verify:
    get:
      summary: Verify a PageVerified Capture key and inspect its credit balance
      operationId: verifyCaptureKey
      security:
        - captureBearer: []
      responses:
        "200": { description: "Valid key, remaining credits, tier and rate limit." }
        "401": { description: Missing or invalid bearer key. }
        "503": { description: Durable Capture store unavailable. }
  /api/v1/capture:
    post:
      summary: Capture a public web page as attested PNG, PDF, or rendered HTML
      operationId: createCapture
      description: Public HTTP(S) targets only. PNG and HTML cost one credit; PDF costs two. A signed artifact link expires after 24 hours.
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url: { type: string, format: uri }
                format: { type: string, enum: [png, pdf, html], default: png }
                full_page: { type: boolean, default: false }
                viewport:
                  type: object
                  required: [width, height]
                  properties:
                    width: { type: integer, minimum: 320, maximum: 2560 }
                    height: { type: integer, minimum: 240, maximum: 2000 }
                attest: { type: boolean, default: true }
      responses:
        "201": { description: "Capture stored with signed artifact URL, SHA-256 digest, timestamp, and optional public evidence URL." }
        "400": { description: Invalid input or blocked private/non-HTTP target. }
        "401": { description: Missing or invalid bearer key. }
        "402": { description: Insufficient credits. }
        "429": { description: Free-key rate limit of ten captures per minute reached. }
        "502": { description: Browser renderer could not complete the capture. }
        "503": { description: Capture storage or renderer unavailable. }
  /api/capture/redeem:
    post:
      summary: Retired Capture pack redemption endpoint
      operationId: retiredCapturePackRedemption
      deprecated: true
      description: Returns HTTP 410 and directs clients to the Stripe Checkout Session claim page.
      responses:
        "410": { description: Gone. Response points to `/capture/claim`. }
  /capture/claim:
    get:
      summary: Collect a one-time Capture key after Stripe checkout
      operationId: claimCapturePurchase
      parameters:
        - name: session_id
          in: query
          required: true
          schema: { type: string, pattern: "^cs_" }
      responses:
        "200": { description: "Paper-receipt page showing a newly claimed key once, an already-collected notice, or a pending webhook notice." }
  /api/capture/refund-request:
    post:
      summary: Queue a Capture or Featured Launch refund request
      operationId: requestCaptureRefund
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                session_id: { type: string, pattern: "^cs_" }
                receipt_email: { type: string, format: email }
                reason: { type: string, minLength: 10, maxLength: 2000 }
      responses:
        "201": { description: Refund request stored with queued status. }
        "400": { description: Missing purchase identity or invalid request fields. }
        "503": { description: Durable Capture store unavailable. }
  /e/{captureId}:
    get:
      summary: Render a public PageVerified Capture evidence receipt
      operationId: getCaptureEvidence
      parameters:
        - name: captureId
          in: path
          required: true
          schema: { type: string, format: uuid }
      responses:
        "200": { description: "Public receipt showing source URL, capture time, format, SHA-256 digest, and honest evidence scope." }
        "404": { description: Public capture evidence not found. }
  /badge/{slug}:
    get:
      summary: Embeddable Attested SVG badge
      operationId: getDirectoryBadge
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string, pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" }
      responses:
        "200":
          description: SVG badge for a verified tool.
          content:
            image/svg+xml:
              schema: { type: string }
        "404": { description: Verified tool not found. }
  /services:
    get:
      summary: List gateway services
      operationId: listServices
      responses:
        "200":
          description: Service entries from the PageVerified index.
          content:
            application/json:
              schema:
                type: object
                required: [services]
                properties:
                  services:
                    type: array
                    items:
                      type: object
  /services/{serviceId}:
    get:
      summary: Get a service manifest by id
      operationId: getService
      parameters:
        - name: serviceId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Service manifest
          content:
            application/json:
              schema:
                $ref: ./schemas/agentstack-service.v0.schema.json
        "404":
          description: Service not found
  /services/{serviceId}/call:
    post:
      summary: Execute a mock-credit gateway call
      operationId: callService
      parameters:
        - name: serviceId
          in: path
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [action, agent_id, principal_id, amount, currency, rail]
              properties:
                action: { type: string }
                agent_id: { type: string }
                principal_id: { type: string }
                amount: { type: number }
                currency: { type: string }
                rail: { type: string }
                payload: { type: object }
      responses:
        "200":
          description: Policy result, ledger event, and receipt. Mock-credit only.
          content:
            application/json:
              schema:
                type: object
                required: [status, policy, ledger_event, receipt]
                properties:
                  status:
                    type: string
                    enum: [allowed, blocked]
                  policy: { type: object }
                  ledger_event:
                    $ref: ./schemas/agentstack-ledger-event.v0.schema.json
                  receipt:
                    $ref: ./schemas/agentstack-receipt.v0.schema.json
  /receipts/{receiptId}:
    get:
      summary: Fetch a generated mock-credit receipt
      operationId: getReceipt
      parameters:
        - name: receiptId
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: Receipt
          content:
            application/json:
              schema:
                $ref: ./schemas/agentstack-receipt.v0.schema.json
        "404":
          description: Receipt not found
  /ledger:
    get:
      summary: Fetch the current mock-credit ledger snapshot
      operationId: getLedger
      responses:
        "200":
          description: Ledger events and receipts stored by the current runtime.
          content:
            application/json:
              schema:
                type: object
                required: [events, receipts]
                properties:
                  events:
                    type: array
                    items:
                      $ref: ./schemas/agentstack-ledger-event.v0.schema.json
                  receipts:
                    type: array
                    items:
                      $ref: ./schemas/agentstack-receipt.v0.schema.json
  /services/pricing.json:
    get:
      summary: Pricing and exclusions
      operationId: getPricing
      responses:
        "200":
          description: Pricing document with Stripe checkout_url fields.
          content:
            application/json:
              schema:
                $ref: ./schemas/agentstack-pricing.v0.schema.json
  /services/policy.json:
    get:
      summary: Validation-stage policy
      operationId: getPolicy
      responses:
        "200":
          description: Policy document
          content:
            application/json:
              schema:
                $ref: ./schemas/agentstack-policy.v0.schema.json
  /schemas/agentstack-readiness-report.v0.schema.json:
    get:
      summary: Readiness report JSON twin schema
      operationId: getReadinessReportSchema
      responses:
        "200":
          description: JSON Schema for paid readiness-report deliverables.
          content:
            application/json:
              schema:
                type: object
  /intake:
    get:
      summary: Static paid-buyer intake form
      operationId: getIntake
      parameters:
        - name: order
          in: query
          required: false
          schema: { type: string }
        - name: tier
          in: query
          required: false
          schema:
            type: string
            enum: [readiness_report, manifest_policy_pack, endpoint_kit]
      responses:
        "200":
          description: HTML mailto intake form.
          content:
            text/html:
              schema: { type: string }
  /t/{slug}:
    get:
      summary: Render a verified directory tool page
      operationId: getDirectoryToolPage
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string, maxLength: 64, pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" }
      responses:
        "200": { description: Tool page HTML with SoftwareApplication schema and the verification record. Outbound links carry rel="sponsored" while a paid featured placement is active. }
        "404": { description: Verified tool not found. }
  /api/stripe-webhook:
    post:
      summary: Stripe checkout completion webhook
      operationId: postStripeWebhook
      description: >
        Verifies Stripe signatures and records checkout.session.completed events.
        Requires STRIPE_WEBHOOK_SECRET in the deployment environment. Current
        Vercel storage is ephemeral unless AGENTSTACK_DATA_DIR is connected to a
        durable sink.
      responses:
        "200":
          description: Event received or ignored.
        "400":
          description: Invalid Stripe signature.
        "500":
          description: Missing webhook secret.
  /llms.txt:
    get:
      summary: Agent-readable text instructions
      operationId: getLlmsTxt
      responses:
        "200":
          description: Agent instructions
          content:
            text/plain:
              schema:
                type: string
  # BEGIN GENERATED attest-tools
  "/api/v1/airports":
    get:
      summary: "Airport reference data"
      operationId: "callAirports"
      description: "Airport reference data. Use when a task needs the static facts about an airport: what an IATA or ICAO code means, where the airport is (city, region, country, coordinates, elevation), whether it has scheduled airline service, which airports a country has, or the straight-line distance and initial bearing between two of them. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/airports"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      parameters:
        - name: "code"
          in: "query"
          required: false
          description: "One IATA (LHR) or ICAO (EGLL) code. Returns that single airport. Cannot be combined with q, country or from/to."
          schema:
            type: "string"
        - name: "q"
          in: "query"
          required: false
          description: "Free-text search over airport, city and code. Returns a list."
          schema:
            type: "string"
        - name: "country"
          in: "query"
          required: false
          description: "ISO 3166-1 alpha-2 country code. Returns that country's airports as a list."
          schema:
            type: "string"
        - name: "from"
          in: "query"
          required: false
          description: "Origin IATA or ICAO code for a distance query. Must be sent with to."
          schema:
            type: "string"
        - name: "to"
          in: "query"
          required: false
          description: "Destination IATA or ICAO code. Must be sent with from."
          schema:
            type: "string"
        - name: "type"
          in: "query"
          required: false
          description: "Filters a q or country list by airport size. Refused on a code or from/to query, which have no list to shape."
          schema:
            type: "string"
        - name: "limit"
          in: "query"
          required: false
          description: "Page size for a q or country list."
          schema:
            type: "integer"
        - name: "offset"
          in: "query"
          required: false
          description: "Rows to skip for a q or country list."
          schema:
            type: "integer"
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "query":
                    description: "The parsed query echoed back, in the same words the response uses."
                  "found":
                    description: "Whether the code matched an airport (code queries)."
                  "matched_on":
                    description: "Which field the code matched: iata or icao."
                  "airport":
                    description: "The matched airport: name, city, region, country, coordinates, elevation and whether it has scheduled service (code queries)."
                  "airports":
                    description: "The page of matching airports (q and country queries)."
                  "count":
                    description: "Rows returned in this page."
                  "total":
                    description: "Rows the query matched in total, so a caller knows whether another page exists."
                  "data_snapshot":
                    description: "The date the bundled OurAirports snapshot was taken."
                  "data_age_days":
                    description: "Whole days between data_snapshot and this call."
                  "notice":
                    description: "What this data is and is not: reference information, not an operational or flight-planning source."
        "400":
          description: "query_required, conflicting_query, from_required, to_required, invalid_q, q_too_long, invalid_country, invalid_type."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
  "/api/v1/jobs/company":
    post:
      summary: "Company open roles"
      operationId: "callCompanyJobs"
      description: "Company open roles. Use when a task needs the roles one named company is hiring for right now: the live list from that company's own Greenhouse, Lever or Ashby job board, with title, location, department, team, employment type, remote flag, posted date and a link to apply, and optionally the description as plain text. Give a board token or the careers-page URL; the provider is detected either way. 2 credits per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/company_jobs"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "company":
                  type: "string"
                  description: "The company's board token, as it appears in its job-board URL. Required unless careers_url is sent."
                "careers_url":
                  type: "string"
                  description: "The company's Greenhouse, Lever or Ashby careers page. The provider and board token are derived from it."
                "provider":
                  type: "string"
                  description: "auto (default), greenhouse, lever or ashby. Refused if it disagrees with careers_url."
                "include_description":
                  type: "boolean"
                  description: "Include each role's description as plain text. Off by default, because it makes the response much larger."
      responses:
        "200":
          description: "Success. 2 credits charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "provider":
                    description: "The job board that answered."
                  "company":
                    description: "The board token the roles were read from."
                  "count":
                    description: "Roles returned."
                  "jobs":
                    description: "Each role: title, location, department, team, employment type, remote flag, posted date and a link to apply."
                  "truncated":
                    description: "Whether the board had more roles than were returned."
                  "source":
                    description: "The board API that was read and the public board URL."
                  "attribution":
                    description: "That the wording is the employer's own, and that PageVerified is not affiliated with the board vendor."
                  "checked_at":
                    description: "When the board was read, not when the request arrived."
        "400":
          description: "company_required, invalid_careers_url, careers_url_unsupported, provider_mismatch, company_mismatch, board_not_found."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "board_rate_limited, board_unavailable."
        "503":
          description: "board_busy."
  "/api/v1/currency/convert":
    post:
      summary: "Currency conversion (reference rates)"
      operationId: "callCurrencyConvert"
      description: "Currency conversion (reference rates). Use when a task needs an indicative conversion of an amount between two of about 30 major currencies (AUD, USD, GBP, JPY, NZD, CAD, CNY and others) at the latest European Central Bank reference rates, for estimates or reports, not for transactions. The ECB publishes the euro rates free of charge on its website. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/currency_convert"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "amount":
                  type: "number"
                  description: "The amount to convert, as a JSON number. A numeric string is refused rather than guessed at."
                "from":
                  type: "string"
                  description: "Three-letter code of the currency the amount is in."
                "to":
                  type: "string"
                  description: "Three-letter code to convert to."
              required: ["amount", "from", "to"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "rate":
                    description: "The rate used, derived from the ECB euro reference rates."
                  "result":
                    description: "The converted amount, rounded for money."
                  "result_raw":
                    description: "The unrounded conversion, for callers doing their own rounding."
                  "rates_date":
                    description: "The date of the ECB rate table used."
                  "source":
                    description: "The ECB table and its date."
                  "source_url":
                    description: "The ECB page the rates are published on, free of charge."
                  "note":
                    description: "That these are indicative reference rates for estimates and reports, not transaction rates."
        "400":
          description: "amount_required, invalid_amount, amount_too_large, unknown_currency, result_too_large."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "rates_unavailable."
  "/api/v1/currency/rates":
    get:
      summary: "Currency reference rates"
      operationId: "callCurrencyRates"
      description: "Currency reference rates. Use when a task needs today's European Central Bank reference exchange rates for about 30 major currencies (AUD, USD, GBP, JPY, NZD, CAD, CNY and others) against any of them as base, for information such as estimates or reports, not for transactions. The ECB publishes the euro rates free of charge on its website. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/currency_rates"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      parameters:
        - name: "base"
          in: "query"
          required: false
          description: "Three-letter code to quote the rates against. Defaults to EUR, the currency the ECB publishes."
          schema:
            type: "string"
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "base":
                    description: "The base currency the rates are quoted against."
                  "rates":
                    description: "One rate per currency in the ECB table."
                  "rates_date":
                    description: "The date of the ECB rate table."
                  "source":
                    description: "The ECB table and its date."
                  "source_url":
                    description: "The ECB page the rates are published on, free of charge."
                  "note":
                    description: "That a non-euro base is derived by cross-rate, and that these are reference rates, not transaction rates."
        "400":
          description: "unknown_currency."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "rates_unavailable."
  "/api/v1/dev":
    post:
      summary: "Developer utilities: cron, regex, UUID, slug and JSON"
      operationId: "callDevUtils"
      description: "Developer utilities: cron, regex, UUID, slug and JSON. Use when a task needs one of the small developer answers that would otherwise cost a round trip to a web tool: the next times a cron expression fires (in a named time zone and in UTC, with a plain-English reading and a note on which non-standard extensions it uses), what a regular expression matches in a piece of text (run on RE2, so no pattern can backtrack its way into exponential time, and a pattern whose compiled program is too large for the input it was given is refused rather than run), fresh UUIDs (version 4, or time-ordered version 7), a URL slug for a title, or JSON pretty-printed, minified or key-sorted with the line and column of a syntax error. Free, and no data is kept. Free per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/dev_utils"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "operation":
                  type: "string"
                  description: "One of cron_next_runs, regex_test, uuid, slugify, json_format. Each one reads its own further fields."
                "expression":
                  type: "string"
                  description: "The cron expression, for cron_next_runs."
                "timezone":
                  type: "string"
                  description: "IANA time zone name for cron_next_runs, such as Europe/London. Defaults to UTC."
                "start":
                  type: "string"
                  description: "ISO instant to start the cron walk from, for cron_next_runs."
                "count":
                  type: "integer"
                  description: "How many cron runs, or how many UUIDs, to return."
                "pattern":
                  type: "string"
                  description: "The regular expression, for regex_test. Run on RE2."
                "flags":
                  type: "string"
                  description: "Distinct letters from i, m, s and u, for regex_test."
                "input":
                  type: "string"
                  description: "The text to run the pattern over, for regex_test."
                "limit":
                  type: "integer"
                  description: "Maximum matches to return, for regex_test."
                "version":
                  type: "integer"
                  description: "4 (random) or 7 (time-ordered), for uuid. Defaults to 4."
                "text":
                  type: "string"
                  description: "The title to slugify, or the JSON document to format."
                "max_length":
                  type: "integer"
                  description: "Cap on the slug length, for slugify."
                "separator":
                  type: "string"
                  description: "The slug separator. Defaults to a hyphen."
                "indent":
                  type: "integer"
                  description: "Spaces per level for json_format; 0 minifies."
                "sort_keys":
                  type: "boolean"
                  description: "Sort object keys, for json_format."
              required: ["operation"]
      responses:
        "200":
          description: "Success. Free charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "operation":
                    description: "The operation that ran."
                  "next_runs":
                    description: "The next fire times, in the named zone and in UTC (cron_next_runs)."
                  "normalized":
                    description: "The cron expression as the parser read it (cron_next_runs)."
                  "matches":
                    description: "The matches found, with their groups and offsets (regex_test)."
                  "engine":
                    description: "The regex engine and version that ran the pattern (regex_test)."
                  "program_size":
                    description: "The compiled program size RE2 produced, which is what the cost guard measures (regex_test)."
                  "uuids":
                    description: "The generated UUIDs (uuid)."
                  "slug":
                    description: "The ASCII slug (slugify)."
                  "unicode_slug":
                    description: "The slug with non-Latin scripts kept (slugify)."
                  "text":
                    description: "The formatted JSON document (json_format)."
                  "limits":
                    description: "The caps this operation applied."
                  "notice":
                    description: "That the answer is computed from the caller's own input and nothing is stored."
        "400":
          description: "operation_required, invalid_operation, invalid_cron, invalid_timezone, invalid_start, invalid_pattern, unsupported_regex, pattern_too_costly, invalid_flags, invalid_version, invalid_json, json_too_deep, output_too_large."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
  "/api/v1/directory/dataset":
    post:
      summary: "Directory dataset"
      operationId: "callDirectoryDataset"
      description: "Directory dataset. Use when an agent needs a paged export or change feed of verified PageVerified directory facts. 10 credits per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/directory_dataset"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "format":
                  type: "string"
                  description: "json (default) or csv. CSV remains inside the JSON response envelope."
                "category":
                  type: "string"
                  description: "A PageVerified directory category slug."
                "since":
                  type: "string"
                  description: "ISO date or timestamp with timezone; includes rows verified OR updated at or after it."
                "cursor":
                  type: "string"
                  description: "Opaque next_cursor from the previous page. Keep category and since unchanged. If matching data changes, restart without a cursor."
                "limit":
                  type: "integer"
                  description: "1–500 rows; defaults to 500. Each successful page costs 10 credits, including an empty page."
      responses:
        "200":
          description: "Success. 10 credits charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "rows":
                    description: "JSON array of whitelisted facts, or CSV text with the same columns (checks is JSON in a cell). Taglines are capped at 160 characters; descriptions and maker data are excluded. CSV formula-like cells get an apostrophe prefix."
                  "next_cursor":
                    description: "Next page token, or null on the last page. Stable slug order; no featured ranking."
                  "total_matching":
                    description: "Unique verified rows matching filters in the supplied listing, before paging; never a fixed advertised count."
                  "generated_at":
                    description: "PageVerified server generation time, not a new verification time."
                  "licence":
                    description: "Data-licence note and verification scope; third-party marks remain with their owners."
        "400":
          description: "invalid_input, invalid_format, invalid_category, invalid_since, invalid_limit, invalid_cursor."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "503":
          description: "services_unavailable, directory_unavailable."
  "/api/v1/directory/search":
    get:
      summary: "Directory search"
      operationId: "callDirectorySearch"
      description: "Directory search. Use when an agent needs to find AI-agent tools (MCP servers, frameworks, browser automation, memory, evals, voice, coding agents and more) by keyword or category before choosing one. Free per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/directory_search"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      parameters:
        - name: "q"
          in: "query"
          required: false
          description: "Keyword to search over the verified tool listings."
          schema:
            type: "string"
        - name: "category"
          in: "query"
          required: false
          description: "One of the PageVerified directory category slugs."
          schema:
            type: "string"
        - name: "limit"
          in: "query"
          required: false
          description: "Maximum tools to return."
          schema:
            type: "integer"
      responses:
        "200":
          description: "Success. Free charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "query":
                    description: "The query as it was read."
                  "count":
                    description: "Tools returned."
                  "tools":
                    description: "Each tool: name, slug, tagline, category, pricing model, its own URL, its PageVerified page, GitHub, verified_at, and whether it holds a paid placement."
                  "ranking":
                    description: "How the results were ordered."
                  "verification_scope":
                    description: "Exactly what Attested means, and what it does not claim."
        "400":
          description: "invalid_category, invalid_limit."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "503":
          description: "services_unavailable."
  "/api/v1/email/check":
    post:
      summary: "Email address check"
      operationId: "callEmailCheck"
      description: "Email address check. Use when an agent needs to screen an email address before a sign-up, lead import or send: syntax, whether the domain can receive mail (MX), disposable domains, role accounts and free mailbox providers — without contacting the mail server. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/email_check"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "email":
                  type: "string"
                  description: "The address to screen. Nothing is sent to the mail server."
              required: ["email"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "email":
                    description: "The address as it was parsed."
                  "domain":
                    description: "The domain part."
                  "syntax_valid":
                    description: "Whether the address parses as a valid address."
                  "mx":
                    description: "The MX records found for the domain."
                  "accepts_mail":
                    description: "Whether the domain publishes a way to receive mail."
                  "implicit_mx":
                    description: "Whether delivery would fall back to the A/AAAA record."
                  "disposable":
                    description: "Whether the domain is on the disposable-domain list."
                  "role_account":
                    description: "Whether the local part is a role account such as info or support."
                  "free_provider":
                    description: "Whether the domain is a free mailbox provider."
                  "verdict":
                    description: "The overall read, with reasons."
                  "mailbox_checked":
                    description: "Always false: the mailbox itself is never probed."
        "400":
          description: "email_required, invalid_email, email_too_long."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "dns_lookup_failed."
  "/api/v1/email/domain-auth":
    post:
      summary: "Email sending-domain check"
      operationId: "callEmailDomainAuth"
      description: "Email sending-domain check. Use when a task needs to know whether a domain is set up to send email that inboxes accept: MX, SPF (with the 10-lookup limit), DKIM keys, DMARC policy, MTA-STS, TLS-RPT and BIMI, with a 0-100 score and plain-English fixes. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/email_domain_auth"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "domain":
                  type: "string"
                  description: "The sending domain to check. Required unless email is sent."
                "email":
                  type: "string"
                  description: "An address to take the domain from. Refused if it disagrees with domain."
                "dkim_selectors":
                  type: "array"
                  description: "Extra DKIM selectors to look up, on top of the common ones this service tries."
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "domain":
                    description: "The domain that was checked."
                  "mx":
                    description: "MX records, including a null MX (RFC 7505)."
                  "spf":
                    description: "The SPF record, its mechanisms and its count against the 10-lookup limit."
                  "dkim":
                    description: "The DKIM keys found, per selector."
                  "dmarc":
                    description: "The DMARC record and its policy."
                  "mta_sts":
                    description: "The MTA-STS record and the policy file when one is advertised."
                  "tls_rpt":
                    description: "The TLS-RPT record."
                  "bimi":
                    description: "The BIMI record."
                  "score":
                    description: "A 0-100 score for the published configuration."
                  "score_breakdown":
                    description: "What each section contributed to the score."
                  "score_unchecked":
                    description: "Sections that could not be checked, so a low score is not read as a failure."
                  "recommendations":
                    description: "Plain-English fixes for what is missing."
        "400":
          description: "domain_required, invalid_domain, invalid_email, domain_email_mismatch, invalid_dkim_selectors, too_many_dkim_selectors."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "dns_lookup_failed."
  "/api/v1/files/convert":
    post:
      summary: "File converter"
      operationId: "callFileConvert"
      description: "File converter. Use when a task has a file in one format and needs it in another: a Word document (.docx) to HTML, Markdown or plain text; HTML to Markdown or plain text; Markdown to HTML; CSV to JSON; JSON to CSV; or CSV and TSV either way. Send the file as a URL or base64, or paste the text. Input is capped at 6 MB, or 1 MB when the target is Markdown, and nothing is stored. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/file_convert"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "from":
                  type: "string"
                  description: "The input format: docx, html, markdown, csv, json or tsv."
                "to":
                  type: "string"
                  description: "The output format. Supported pairs are returned on every response and on an unsupported_conversion error."
                "text":
                  type: "string"
                  description: "The document as text. Not accepted for docx, which is binary."
                "url":
                  type: "string"
                  description: "A public http(s) URL to read the document from."
                "file_base64":
                  type: "string"
                  description: "The document as base64. Exactly one of text, url or file_base64."
              required: ["from", "to"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "result_text":
                    description: "The converted document."
                  "from":
                    description: "The input format."
                  "to":
                    description: "The output format."
                  "input_source":
                    description: "Which of text, url or file_base64 was used."
                  "input_encoding":
                    description: "The character encoding the input was read as."
                  "bytes_in":
                    description: "Bytes read."
                  "bytes_out":
                    description: "Bytes produced."
                  "truncated":
                    description: "Whether the output was cut at a cap."
                  "stats":
                    description: "Counts from the conversion, such as rows and columns for tabular formats."
                  "warnings":
                    description: "What was dropped or changed in the conversion."
                  "limits":
                    description: "The caps that applied to this conversion."
                  "supported_pairs":
                    description: "Every from -> to pair this service converts."
        "400":
          description: "unsupported_conversion, input_required, too_many_inputs, text_input_not_supported, input_too_large, invalid_file_base64, invalid_json, json_not_tabular, invalid_docx, compression_ratio_rejected."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "source_http_error."
  "/api/v1/links/verify":
    post:
      summary: "Backlink check"
      operationId: "callLinksVerify"
      description: "Backlink check. Use when a task needs to confirm that a page links to a site or URL: whether the link is there, whether it is followed (no nofollow, sponsored or ugc) and whether the linking page can be indexed, based on Google's published robots and link rules. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/links_verify"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "page_url":
                  type: "string"
                  description: "The public page that should carry the link."
                "target":
                  type: "string"
                  description: "The site or URL the link should point at."
              required: ["page_url", "target"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "found":
                    description: "Whether a link to the target is on the page."
                  "match_count":
                    description: "How many matching links were found."
                  "links":
                    description: "Each matching link: href, anchor text, rel and whether it is followed."
                  "anchors_scanned":
                    description: "How many links on the page were examined."
                  "page":
                    description: "Whether the page can be indexed, per its robots meta tag and X-Robots-Tag."
                  "page":
                    description: "Whether a page-level nofollow applies to its links."
                  "page":
                    description: "The robots rules read from the page."
                  "page":
                    description: "The robots rules read from the response headers."
                  "page":
                    description: "The canonical URL the page declares, and whether it matches the page."
                  "verdict":
                    description: "The overall read of the link."
                  "final_url":
                    description: "The URL after redirects."
                  "http_status":
                    description: "The status the page returned."
        "400":
          description: "page_url_required, invalid_page_url, page_url_too_long, target_required, invalid_target."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "fetch_failed."
  "/api/v1/media/open-search":
    get:
      summary: "Public-domain art and media search"
      operationId: "callOpenMediaSearch"
      description: "Public-domain art and media search. Use when a task needs an image or artwork that is free to use: public-domain works from The Metropolitan Museum of Art and the Art Institute of Chicago, each with title, artist, date, medium, a full-size image URL, a thumbnail, the museum's page for the work, the licence the museum publishes and a ready-made credit line. Only items the museum itself flags as public domain are returned. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/open_media_search"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      parameters:
        - name: "q"
          in: "query"
          required: true
          description: "What to search the museum collections for."
          schema:
            type: "string"
        - name: "source"
          in: "query"
          required: false
          description: "all (default), met for The Metropolitan Museum of Art, or aic for the Art Institute of Chicago."
          schema:
            type: "string"
        - name: "limit"
          in: "query"
          required: false
          description: "Maximum items to return."
          schema:
            type: "integer"
        - name: "has_image"
          in: "query"
          required: false
          description: "Only return items that have an image. On by default."
          schema:
            type: "boolean"
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "query":
                    description: "The query as it was read."
                  "count":
                    description: "Items returned."
                  "items":
                    description: "Each work: title, artist, date, medium, a full-size image URL, a thumbnail, the museum's page for it, the licence the museum publishes and a ready-made credit line."
                  "truncated":
                    description: "Whether a museum held more than was returned."
                  "sources":
                    description: "The museums that answered, with their own licence terms."
                  "sources_unavailable":
                    description: "Museums that did not answer, so an empty result is never read as nothing existing."
                  "attribution":
                    description: "That the values are each museum's own, and that PageVerified is not affiliated with either museum."
        "400":
          description: "q_required, invalid_q."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "source_unavailable, source_response_unreadable."
  "/api/v1/phone/parse":
    post:
      summary: "Phone number check"
      operationId: "callPhoneParse"
      description: "Phone number check. Use when a task needs to know whether a phone number is valid for its country, what kind of number it is (mobile, landline, toll-free, premium rate, VoIP) and its E.164, national and international formats. Formats, country and type are only returned for valid numbers; an invalid number keeps its E.164 form only when its length is possible, and e164 is null for any number longer than the 15 digits E.164 allows. The phone input may be a plain number or an RFC 3966 tel: URI, so the uri from an earlier answer can be fed straight back in. Checked offline: no carrier or live-line lookup. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/phone_parse"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "phone":
                  type: "string"
                  description: "The number, as digits or as an RFC 3966 tel: URI, so the uri from an earlier answer can be fed straight back in."
                "default_country":
                  type: "string"
                  description: "ISO 3166-1 alpha-2 region code to read a national-format number against."
              required: ["phone"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "valid":
                    description: "Whether the number is valid for its country."
                  "possible":
                    description: "Whether the length is possible even when the number is not valid."
                  "reason":
                    description: "Why an invalid number was rejected."
                  "e164":
                    description: "The E.164 form. Null for any number longer than the 15 digits E.164 allows."
                  "national":
                    description: "The national format, for valid numbers."
                  "international":
                    description: "The international format, for valid numbers."
                  "country":
                    description: "The country the number belongs to, for valid numbers."
                  "country_calling_code":
                    description: "The calling code."
                  "type":
                    description: "Mobile, landline, toll-free, premium rate, VoIP and so on, for valid numbers."
                  "extension":
                    description: "Any extension carried on the number."
                  "uri":
                    description: "The RFC 3966 tel: URI for the number."
        "400":
          description: "phone_required, invalid_phone, phone_too_long, invalid_default_country."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
  "/api/v1/sheets/build":
    post:
      summary: "Spreadsheet builder"
      operationId: "callSheetsBuild"
      description: "Spreadsheet builder. Use when a task has to hand back a real spreadsheet rather than a wall of rows: typed columns (text, number, date, currency, percent) with number formats applied, a bold header, optional frozen header row, column widths and an autofilter, returned as a base64 .xlsx or .csv. Up to 10 sheets and 50,000 cells in total (the header row counts). Values that could be read back as formulas are neutralised. Dates go in as YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS; percent cells store a fraction (0.15 is 15%) unless the column sets percent_basis to \"percent\". CSV takes one sheet. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/sheets_build"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "format":
                  type: "string"
                  description: "xlsx (default) or csv. CSV takes one sheet."
                "sheets":
                  type: "array"
                  description: "Up to 10 sheets. Each has a name, a columns list and an optional rows list, plus freeze_header and autofilter flags."
                "sheets[].columns":
                  type: "array"
                  description: "Each column: key, label and type (text, number, date, currency, percent), with optional width and percent_basis."
                "sheets[].rows":
                  type: "array"
                  description: "Each row is an object keyed by column key. Up to 50,000 cells in total, header row included."
              required: ["sheets", "sheets[].columns"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "format":
                    description: "The format produced."
                  "content_type":
                    description: "The media type of the produced file."
                  "filename":
                    description: "A suggested file name."
                  "sheets":
                    description: "Each sheet with its row and column counts."
                  "cells_written":
                    description: "Cells written."
                  "cells_repaired":
                    description: "Cells where characters no XML document can hold were dropped."
                  "formula_guard":
                    description: "How many cells carry the formula guard, what triggers it and how it is applied."
                  "dates":
                    description: "How dates are stored in this format."
                  "text_storage":
                    description: "How text is stored in this format."
                  "bytes":
                    description: "Size of the produced file."
                  "sha256":
                    description: "SHA-256 of the produced bytes. The same rows always produce the same hash."
                  "file_base64":
                    description: "The produced file."
        "400":
          description: "sheets_required, invalid_format, csv_multiple_sheets, too_many_sheets, columns_required, too_many_columns, too_many_rows, too_many_cells, input_too_large."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "413":
          description: "output_too_large."
  "/api/v1/subtitles":
    post:
      summary: "Subtitle tools: convert, retime, merge and read caption files"
      operationId: "callSubtitleTools"
      description: "Subtitle tools: convert, retime, merge and read caption files. Use when a task involves a subtitle or caption file: converting between SubRip (.srt), WebVTT (.vtt), ASS/SSA and YouTube SBV, shifting timings or rescaling them for a frame-rate change (23.976 to 25 and back), merging several files onto one timeline, pulling a plain-text transcript out of captions, or reporting a file's cue count, duration and reading speed. The converted file comes back in result_text; the info operation leaves result_text empty and answers in the info block. Send the file as text, as a public URL, or as base64 up to 4 MB. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/subtitle_tools"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "operation":
                  type: "string"
                  description: "convert (default), shift, merge, to_text or info."
                "text":
                  type: "string"
                  description: "The caption file as text. Not allowed with operation merge."
                "url":
                  type: "string"
                  description: "A public http(s) URL to read the caption file from."
                "file_base64":
                  type: "string"
                  description: "The caption file as base64, up to 4 MB."
                "files":
                  type: "array"
                  description: "The files to merge onto one timeline. merge only."
                "from_format":
                  type: "string"
                  description: "auto (default), srt, vtt, ass or sbv."
                "to_format":
                  type: "string"
                  description: "srt, vtt, ass or sbv. Required for convert; refused for info and to_text."
                "offset_seconds":
                  type: "number"
                  description: "Seconds to shift every cue, for operation shift."
                "scale":
                  type: "number"
                  description: "Timing multiplier for a frame-rate change, for operation shift."
                "merge_gap_seconds":
                  type: "number"
                  description: "Gap to leave between files, for operation merge."
                "strip_tags":
                  type: "boolean"
                  description: "Drop styling tags from the cue text."
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "operation":
                    description: "The operation that ran."
                  "from_format":
                    description: "The format the file was read as."
                  "to_format":
                    description: "The format written, or null for info and to_text."
                  "cues":
                    description: "Cue count."
                  "duration_seconds":
                    description: "Where the last cue ends."
                  "result_text":
                    description: "The converted file, the transcript, or empty for operation info."
                  "truncated":
                    description: "Whether the output stopped at a cap."
                  "applied":
                    description: "The offset, scale, merge gap, tag stripping and file count actually applied."
                  "info":
                    description: "Cue count, duration and reading speed."
                  "warnings":
                    description: "What the parser had to repair or drop."
                  "limits":
                    description: "The caps that applied."
                  "sources":
                    description: "The format specifications this parser and writer follow."
        "400":
          description: "text_required, conflicting_input, files_not_allowed, files_required, too_few_files, to_format_required, to_format_not_allowed, invalid_to_format, offset_or_scale_required, unknown_subtitle_format, too_many_cues, input_too_large."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "fetch_failed."
  "/api/v1/techstack":
    post:
      summary: "Tech Stack lookup"
      operationId: "callTechstack"
      description: "Tech Stack lookup. Use when a task depends on what a website is built with: CMS, ecommerce platform, hosting, analytics, ad pixels, payments, chat or forms. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/techstack"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "url":
                  type: "string"
                  description: "The public http(s) page to look up. A bare domain is treated as https://."
              required: ["url"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "url":
                    description: "The URL as it was read."
                  "final_url":
                    description: "The URL after redirects."
                  "http_status":
                    description: "The status the page returned."
                  "technologies":
                    description: "Each detection: name, category, confidence and the header, cookie or page snippet that proved it."
                  "checked_at":
                    description: "When the page was fetched."
        "400":
          description: "url_required, invalid_url, private_address_not_allowed, unsupported_content_type, response_too_large, redirect_limit_exceeded."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "fetch_timeout, fetch_failed."
  "/api/v1/diff":
    post:
      summary: "Text and JSON compare"
      operationId: "callTextDiff"
      description: "Text and JSON compare. Use when a task needs to know exactly what changed between two versions of a text, document, config file or JSON payload: line, word or character changes with a unified patch, or a JSON Pointer list of structural changes. Inputs are capped at 1,000,000 characters a side and 1,500,000 combined; lines and words mode handle that whole range, while chars mode on a heavily rewritten document falls back to block-level changes (coarse: true in the response) rather than taking longer. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/text_diff"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "a":
                  type: "string"
                  description: "The first version. Up to 1,000,000 characters."
                "b":
                  type: "string"
                  description: "The second version. a and b together are capped at 1,500,000 characters."
                "mode":
                  type: "string"
                  description: "lines (default), words, chars or json."
                "ignore_whitespace":
                  type: "boolean"
                  description: "Treat runs of whitespace as equal."
                "ignore_case":
                  type: "boolean"
                  description: "Compare without case."
                "context_lines":
                  type: "integer"
                  description: "Lines of context in the unified patch, 0-20."
              required: ["a", "b"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "mode":
                    description: "The mode that ran."
                  "unit":
                    description: "What a change is counted in: lines, words, characters or JSON pointers."
                  "identical":
                    description: "Whether the two sides are the same."
                  "stats":
                    description: "Added, removed and, for json, changed counts."
                  "changes":
                    description: "Each change, with its position."
                  "unified_patch":
                    description: "A unified diff, for the text modes."
                  "coarse":
                    description: "True when chars mode fell back to block-level changes rather than taking longer."
                  "truncated":
                    description: "Whether the change list stopped at a cap."
                  "options":
                    description: "The options that were applied."
        "400":
          description: "a_required, b_required, input_too_long, too_many_lines, invalid_json_a, invalid_json_b, json_too_deep."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "diff_too_complex."
  "/api/v1/text/stats":
    post:
      summary: "Text Stats: words, characters, tokens and SMS segments"
      operationId: "callTextStats"
      description: "Text Stats: words, characters, tokens and SMS segments. Use when a task needs counts for a piece of text: words, user-perceived characters, bytes, sentences, paragraphs, lines, reading or speaking time, OpenAI token counts, SMS segments, or a check against length limits such as a character, word, SMS or prompt-token budget. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/text_stats"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "text":
                  type: "string"
                  description: "The text to count. Up to 200,000 UTF-16 code units. Whitespace-only text is valid and counts zero words."
                "limits":
                  type: "array"
                  description: "Up to 20 budgets to check the text against. Each is { name, max, unit } where unit is characters, words, tokens_o200k, tokens_cl100k, bytes or sms_segments."
              required: ["text"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "characters":
                    description: "User-perceived characters (graphemes)."
                  "code_points":
                    description: "Unicode code points."
                  "utf16_units":
                    description: "JavaScript string length."
                  "bytes_utf8":
                    description: "UTF-8 byte length."
                  "words":
                    description: "Word count."
                  "sentences":
                    description: "Sentence count."
                  "paragraphs":
                    description: "Paragraph count."
                  "lines":
                    description: "Line count."
                  "reading_time_minutes":
                    description: "At 238 words per minute, adult silent reading of non-fiction."
                  "speaking_time_minutes":
                    description: "At 183 words per minute, adult reading aloud."
                  "tokens":
                    description: "OpenAI o200k_base and cl100k_base token counts, with a note on which models each is listed for."
                  "sms":
                    description: "SMS encoding, segment count and concatenation limit, with the assumptions spelled out."
                  "limits":
                    description: "Each budget sent, with the measured value and whether it fits."
                  "sources":
                    description: "The research and specifications behind the reading, token and SMS figures."
        "400":
          description: "text_required, invalid_text, text_too_long, invalid_limits, too_many_limits, invalid_limit_unit, invalid_limit_max, limit_name_required."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
  "/api/v1/read":
    post:
      summary: "Read a page as Markdown"
      operationId: "callUrlMarkdown"
      description: "Read a page as Markdown. Use when a task needs the readable text of one web page instead of its HTML: an article, a documentation page, a changelog or a product page, returned as Markdown with its headings, lists, tables and code blocks intact, plus the page's title, byline, language and links. 1 credit per successful call from the shared PageVerified credit balance. Docs: https://pageverified.com/tools/url_markdown"
      tags:
        - "PageVerified tools"
      security:
        - captureBearer: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: "object"
              properties:
                "url":
                  type: "string"
                  description: "The public http(s) page to read."
                "include_links":
                  type: "boolean"
                  description: "Return the page's links as a list. On by default."
                "include_images":
                  type: "boolean"
                  description: "Return the page's images as a list. Off by default."
                "max_chars":
                  type: "integer"
                  description: "Cap on the Markdown returned."
              required: ["url"]
      responses:
        "200":
          description: "Success. 1 credit charged from the shared PageVerified balance."
          content:
            application/json:
              schema:
                type: "object"
                properties:
                  call_id:
                    type: "string"
                    description: "Receipt id for this call."
                  credits_charged:
                    type: "integer"
                    description: "Credits taken for this call."
                  credits_remaining:
                    type: "integer"
                    description: "Credits left on the key."
                  "markdown":
                    description: "The readable article as Markdown, with headings, lists, tables and code blocks intact."
                  "title":
                    description: "The page title."
                  "byline":
                    description: "The byline, when the page marks one."
                  "site_name":
                    description: "The site name, when the page declares one."
                  "published_at":
                    description: "The publication date, when the page declares one."
                  "lang":
                    description: "The page language."
                  "word_count":
                    description: "Words in the whole article, even when the Markdown was cut."
                  "truncated":
                    description: "Whether max_chars or the extraction budget cut the Markdown."
                  "extracted_by":
                    description: "Which extractor produced the article."
                  "links":
                    description: "The page's links, when include_links is on."
                  "images":
                    description: "The page's images, when include_images is on."
                  "final_url":
                    description: "The URL after redirects."
                  "http_status":
                    description: "The status the page returned."
        "400":
          description: "url_required, invalid_url, private_address_not_allowed, unsupported_content_type, response_too_large."
        "401":
          description: "invalid_api_key — the key is missing or unknown."
        "402":
          description: "insufficient_credits — with credits_required and credits_remaining."
        "429":
          description: "rate_limit_exceeded — with limit and window_seconds."
        "502":
          description: "fetch_timeout, fetch_failed."
        "422":
          description: "page_too_complex, page_too_slow."
  # END GENERATED attest-tools

components:
  securitySchemes:
    captureBearer:
      type: http
      scheme: bearer
      bearerFormat: PageVerified Capture API key
