{
 "openapi": "3.1.0",
 "info": {
  "title": "Vouch API",
  "version": "1.0.0",
  "description": "Vouch checks links and quotes against the live web: which links load, redirect, 404, soft-404 or point to a missing #anchor (with the closest real page from the site's sitemap), and whether a page really contains a quote, word for word or with changed words and numbers. No account.",
  "contact": {
   "name": "Clawhard Studio",
   "url": "https://clawhard.com",
   "email": "support@clawhard.com"
  }
 },
 "servers": [
  {
   "url": "https://vouch.clawhard.com"
  }
 ],
 "paths": {
  "/api/v1/check_links": {
   "post": {
    "operationId": "check_links",
    "summary": "Check that links load, where they redirect and whether #anchors exist",
    "description": "Use when the user asks whether links work, or before links, sources or doc URLs go into an answer, README, report, email or code comment (signals: \"are these links dead\", \"check the links in this README\", \"does this URL exist\", \"404\", \"broken link\", \"where does this redirect\", \"is this docs page…",
    "x-full-description": "Use when the user asks whether links work, or before links, sources or doc URLs go into an answer, README, report, email or code comment (signals: \"are these links dead\", \"check the links in this README\", \"does this URL exist\", \"404\", \"broken link\", \"where does this redirect\", \"is this docs page still there\"). Fetches each URL live (GET, redirects followed hop by hop) and returns per link a status: ok, redirected (link the final_url), soft_404 (answers 200 but the title says not found, or a deep link lands on the front page), anchor_missing (the #section id is not on the page), broken (404, 410 or other 4xx), server_error (5xx), blocked (401, 403, 429 or a bot challenge: not proof the page is missing), unreachable (DNS, connection or timeout) or invalid. Each result has http_status, every hop, final_url, page title and canonical; for broken pages it lists the closest real pages from the site's own sitemap (suggestions, the top one re-checked). Give urls (up to 15) or text (Markdown, HTML or plain text; its http and https links are extracted, first 15 checked). Example: {\"urls\":[\"https://docs.stripe.com/api/charge\",\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes\"]}. Limits: a page can work in a browser and still be blocked here; pages built by JavaScript may hide anchors; one call makes at most 45 requests. Returns: {summary, verdict: all_ok|check|problems, counts:{<status>:n}, results:[{url, status, meaning, http_status, final_url, redirects, hops:[{url,status}], title?, canonical?, content_type?, anchor?:{id,found,note?}, note?, suggestions?:[{url,score,http_status?}], suggestions_from?, suggestions_note?}], links_found?, not_checked?, engine, checked_at, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "urls": {
          "type": "array",
          "minItems": 1,
          "maxItems": 15,
          "items": {
           "type": "string",
           "minLength": 4,
           "maxLength": 2000
          },
          "description": "Up to 15 http or https addresses. A #fragment is checked as an anchor on the page. Give urls or text, not both."
         },
         "text": {
          "type": "string",
          "minLength": 10,
          "maxLength": 200000,
          "description": "Markdown, HTML or plain text (a README, an answer, a doc); every http/https link in it is extracted and the first 15 unique ones are checked. Give urls or text, not both."
         },
         "suggest": {
          "type": "boolean",
          "description": "true (default): for broken pages, look up the closest pages in the site's sitemap.xml. false: skip that lookup."
         }
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/check_quote": {
   "post": {
    "operationId": "check_quote",
    "summary": "Check whether a web page really contains a quote",
    "description": "Use when a quote, a statistic or a claim is attributed to a web page and the user asks whether the source says it, or before a citation goes into an answer, report, article or essay (signals: \"does this article actually say\", \"verify this quote\", \"is this citation real\", \"check the source\", \"did…",
    "x-full-description": "Use when a quote, a statistic or a claim is attributed to a web page and the user asks whether the source says it, or before a citation goes into an answer, report, article or essay (signals: \"does this article actually say\", \"verify this quote\", \"is this citation real\", \"check the source\", \"did they really write that\", \"fact-check this quote against the link\"). Fetches the page once, extracts its visible text and returns per quote a verdict: exact (word for word), normalized (same words in order; only punctuation, capitals, spacing or curly quotes differ), close (similarity 0.85 or more, wording differs), partial (0.5 to 0.85) or not_found, with the matching passage, surrounding context, the words that differ and numbers_differ when a number changed (for example 1914 in the quote, 1912 on the page). Quotes with \"...\" are checked part by part. Example: {\"url\":\"https://en.wikipedia.org/wiki/Alan_Turing\",\"quotes\":[\"widely regarded as the father of theoretical computer science\"]}. Limits: a match shows the words are on the page, not that the claim is true; pages built by JavaScript may have little text in their HTML; PDFs and paywalled or bot-blocked pages cannot be read; up to 10 quotes of 1000 characters, at least 3 words each. Returns: {summary, verdict: all_found|wording_differs|not_supported, counts:{<verdict>:n}, url, title, http_status, page_characters, results:[{quote, verdict: exact|normalized|close|partial|not_found, similarity, passage, context, differences?:[{quote,page}], numbers_differ?, note?, parts?}], notes, engine, checked_at, open_url}",
    "x-openai-isConsequential": false,
    "responses": {
     "200": {
      "description": "Result. Always has \"ok\": true.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          }
         },
         "additionalProperties": true
        }
       }
      }
     },
     "400": {
      "description": "Bad input. {\"ok\":false,\"error\":\"...\"}"
     },
     "429": {
      "description": "Rate limited. Retry after the Retry-After header."
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "url",
         "quotes"
        ],
        "properties": {
         "url": {
          "type": "string",
          "minLength": 4,
          "maxLength": 2000,
          "description": "The http or https address of the source page (an article, doc, blog post, Wikipedia page or plain-text file)."
         },
         "quotes": {
          "type": "array",
          "minItems": 1,
          "maxItems": 10,
          "items": {
           "type": "string",
           "minLength": 8,
           "maxLength": 1000
          },
          "description": "1 to 10 quotes or claims to look for, as written in the draft (at least 3 words each)."
         }
        }
       }
      }
     }
    }
   }
  }
 },
 "externalDocs": {
  "description": "llms.txt",
  "url": "https://vouch.clawhard.com/llms.txt"
 }
}