{"openapi":"3.1.0","info":{"title":"Markdown Viewer API","version":"1.0.0","description":"REST API for rendering, formatting, analyzing, and validating markdown — plus conversion, extraction, audit, and transform utilities. Authenticate with `Authorization: Bearer <API_KEY>`.","termsOfService":"https://trymarkdownviewer.com/terms","contact":{"name":"Markdown Viewer","url":"https://trymarkdownviewer.com"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"}},"externalDocs":{"description":"Human-readable API documentation","url":"https://trymarkdownviewer.com/docs"},"servers":[{"url":"https://trymarkdownviewer.com","description":"Production"}],"tags":[{"name":"Core","description":"Core endpoints for the Markdown Viewer API."},{"name":"Convert","description":"Convert endpoints for the Markdown Viewer API."},{"name":"Extract","description":"Extract endpoints for the Markdown Viewer API."},{"name":"Generate","description":"Generate endpoints for the Markdown Viewer API."},{"name":"Audit","description":"Audit endpoints for the Markdown Viewer API."},{"name":"Transform","description":"Transform endpoints for the Markdown Viewer API."},{"name":"Diff","description":"Diff endpoints for the Markdown Viewer API."},{"name":"Metrics","description":"Metrics endpoints for the Markdown Viewer API."},{"name":"Platform","description":"Platform and operational endpoints."}],"paths":{"/api/v1/render":{"post":{"operationId":"render","summary":"Render markdown","description":"Renders a markdown document into HTML. Output is sanitised with DOMPurify — script tags, inline event handlers, and `javascript:` URLs are removed. Supports CommonMark plus GitHub Flavored Markdown (tables, task lists, strikethrough, autolinks, fenced code).\n\nDocumentation: https://trymarkdownviewer.com/docs/api-render","tags":["Core"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source. Max 256 KiB.","type":"string"},"sanitize":{"description":"Reserved. Output is always sanitised today.","type":"boolean"}},"required":["markdown"]},"example":{"markdown":"# Hello world\n\nWelcome to **Markdown Viewer**."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"html":"<h1 id=\"hello-world\">Hello world</h1>\n<p>Welcome to <strong>Markdown Viewer</strong>.</p>","characters":78}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/format":{"post":{"operationId":"format","summary":"Format markdown","description":"Applies a conservative set of fixes: trims trailing whitespace, normalises bullet style to `-`, collapses 3+ blank lines into one, ensures a space after ATX heading hashes, and normalises task-list checkboxes.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-format","tags":["Core"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"##Heading\n*  item one\n\n\n* item two"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"formatted":"## Heading\n\n- item one\n\n- item two\n","changed":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/analyze":{"post":{"operationId":"analyze","summary":"Analyze markdown","description":"Returns a structural and readability report for the document. Counts headings, links, images, code blocks, and tables; computes an approximate Flesch reading-ease score; surfaces top non-stopword frequencies.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-analyze","tags":["Core"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# Title\n\nA short example with a [link](https://example.com)."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"wordCount":8,"readingTimeMinutes":1,"readabilityScore":92,"readabilityLabel":"Very easy","headings":[{"level":1,"text":"Title","id":"title","line":1}],"links":[{"url":"https://example.com","line":3,"label":"link"}],"images":[],"tableCount":0,"codeBlockCount":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/validate":{"post":{"operationId":"validate","summary":"Validate markdown","description":"Runs a conservative linter that reports heading-increment jumps, missing spaces after `#`, inconsistent bullets, multiple blank lines in a row, and trailing whitespace. Each issue points to a specific line number and rule id you can act on.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-validate","tags":["Core"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"##Heading\n\n\n\n*  bullet"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"valid":false,"issueCount":2,"issues":[{"line":1,"message":"Missing space after `#` in heading.","rule":"heading-space","severity":"warning"},{"line":5,"message":"Use `-` for unordered list items.","rule":"consistent-bullets","severity":"info"}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/convert/html-to-markdown":{"post":{"operationId":"convert_html_to_markdown","summary":"HTML → Markdown","description":"Server-side HTML to Markdown converter — no jsdom, no headless browser. Handles headings, paragraphs, lists, tables, blockquotes, links, images, fenced code blocks, and basic inline formatting. Strips `<script>`, `<style>`, and `<noscript>` automatically.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-convert-html-to-markdown","tags":["Convert"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"html":{"description":"HTML source. Max 512 KiB.","type":"string"}},"required":["html"]},"example":{"html":"<h1>Hello</h1><p>Welcome to <strong>Markdown Viewer</strong>.</p>"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"markdown":"# Hello\n\nWelcome to **Markdown Viewer**.\n","characters":47}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/convert/markdown-to-text":{"post":{"operationId":"convert_markdown_to_text","summary":"Markdown → Plain text","description":"Removes all markdown syntax — headings, emphasis, code fences, links, images, tables, lists, blockquotes — and returns plain text. Useful for email previews, SMS, OG descriptions, search indexing, and accessibility tooling.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-convert-markdown-to-text","tags":["Convert"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# Hello\n\nVisit **[the site](https://example.com)**."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"text":"Hello\n\nVisit the site.","characters":22,"words":4}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/convert/csv-to-table":{"post":{"operationId":"convert_csv_to_table","summary":"CSV → Markdown table","description":"RFC-4180-compliant CSV parser. Quoted fields, embedded newlines, and escaped quotes are handled correctly. The first row becomes the table header.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-convert-csv-to-table","tags":["Convert"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"description":"CSV/TSV source. Max 512 KiB.","type":"string"},"delimiter":{"description":"Field delimiter. Defaults to comma.","type":"string","enum":[",","\\t"]}},"required":["csv"]},"example":{"csv":"name,age\nAda,36\nLinus,54"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"markdown":"| name | age |\n| --- | --- |\n| Ada | 36 |\n| Linus | 54 |\n","rows":3,"columns":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/convert/table-to-csv":{"post":{"operationId":"convert_table_to_csv","summary":"Markdown table → CSV","description":"Finds the first GFM pipe table in the document and emits CSV or TSV. Cells that contain the delimiter, quotes, or newlines are escaped per RFC 4180.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-convert-table-to-csv","tags":["Convert"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"delimiter":{"description":"Field delimiter. Defaults to comma.","type":"string","enum":[",","\\t"]}},"required":["markdown"]},"example":{"markdown":"| a | b |\n|---|---|\n| 1 | 2 |\n"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"csv":"a,b\r\n1,2\r\n","rows":2,"columns":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/convert/json-to-markdown":{"post":{"operationId":"convert_json_to_markdown","summary":"JSON → Markdown","description":"Array of flat objects → pipe table. Anything else → nested bullet list with bold keys. Two predictable shapes; no surprises.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-convert-json-to-markdown","tags":["Convert"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"json":{"description":"JSON source.","type":"string"},"mode":{"description":"Force a specific rendering. Defaults to 'table' (falls back to list).","type":"string","enum":["table","list"]}},"required":["json"]},"example":{"json":"[{\"name\":\"Ada\",\"age\":36}]"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"markdown":"| name | age |\n| --- | --- |\n| Ada | 36 |\n","mode":"table"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/outline":{"post":{"operationId":"extract_outline","summary":"Extract outline","description":"Pull the document's heading hierarchy (h1 through h6). Each item has a level, text, GitHub-style slug `id`, and 1-based line number. The slug ids match the anchors emitted by /api/v1/render.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-outline","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# Title\n\n## Section"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"headings":[{"level":1,"text":"Title","id":"title","line":1},{"level":2,"text":"Section","id":"section","line":3}],"count":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/links":{"post":{"operationId":"extract_links","summary":"Extract links","description":"Classify every link in a document — anchor / external / relative / mailto / image / empty — and flag structural issues like broken in-document anchors, missing alt text on images, and empty link labels.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-links","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"See [docs](#docs) and [home](https://example.com)."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"links":[{"line":1,"text":"docs","url":"#docs","kind":"anchor","status":"error","note":"Anchor #docs does not match any heading in this document."},{"line":1,"text":"home","url":"https://example.com","kind":"external","status":"ok"}],"totals":{"count":2,"ok":1,"warn":0,"error":1}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/images":{"post":{"operationId":"extract_images","summary":"Extract images","description":"Find every image reference (inline + reference-style). Each result includes alt text, URL, whether the source is external/absolute/data URI, and whether the alt text is present.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-images","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"![diagram](https://example.com/x.png)"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"images":[{"line":1,"alt":"diagram","url":"https://example.com/x.png","kind":"inline","isExternal":true,"isAbsolute":false,"isData":false,"hasAlt":true}],"totals":{"count":1,"missingAlt":0,"external":1,"relative":0,"data":0,"duplicates":0}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/code-blocks":{"post":{"operationId":"extract_code_blocks","summary":"Extract code blocks","description":"Pull every fenced code block out as a structured object: language tag, source body, start line, and a suggested filename based on the language. Ideal for snippet runners, docs validators, and AI tooling.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-code-blocks","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"```js\nconsole.log(1);\n```"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"blocks":[{"index":1,"lang":"js","startLine":1,"body":"console.log(1);","suggestedFilename":"snippet-1.js"}],"count":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/tasks":{"post":{"operationId":"extract_tasks","summary":"Extract tasks","description":"Collect every GFM task-list item (`- [ ]` / `- [x]`) along with its parent heading. Returns totals and percent complete — perfect for progress badges in READMEs or project dashboards.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-tasks","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"## TODO\n- [x] one\n- [ ] two"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"tasks":[{"line":2,"done":true,"text":"one","section":"TODO"},{"line":3,"done":false,"text":"two","section":"TODO"}],"total":2,"done":1,"open":1,"percent":50}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/urls":{"post":{"operationId":"extract_urls","summary":"Extract URLs","description":"Collect every external/relative URL across the document — both markdown link syntax and bare URLs in body text — deduped with counts and line numbers per appearance.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-urls","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"[a](https://example.com)\nVisit https://example.com again."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"urls":[{"url":"https://example.com","count":2,"lines":[1],"kind":"external"}],"count":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/extract/frontmatter":{"post":{"operationId":"extract_frontmatter","summary":"Extract frontmatter","description":"Parses `---`-delimited YAML frontmatter at the top of a document. Supports strings, numbers, booleans, and simple inline arrays — matching the subset used by Jekyll, Hugo, Next.js MDX, Astro, and most static site generators.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-extract-frontmatter","tags":["Extract"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"---\ntitle: Hello\ntags: [a, b]\n---\nBody."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"frontmatter":{"title":"Hello","tags":["a","b"]},"body":"Body.","raw":"title: Hello\ntags: [a, b]","hasFrontmatter":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/generate/toc":{"post":{"operationId":"generate_toc","summary":"Generate table of contents","description":"Build a Markdown TOC ready to paste into a README or inject between `<!-- TOC -->` markers. Level range, ordered vs. unordered, marker style, and indentation are all configurable.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-generate-toc","tags":["Generate"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"minLevel":{"description":"Lowest heading level to include. Default 2.","type":"string"},"maxLevel":{"description":"Highest heading level to include. Default 6.","type":"string"},"ordered":{"description":"Use `1.` instead of `-`.","type":"boolean"},"marker":{"description":"Unordered list marker.","type":"string","enum":["-","*","+"]},"indentSize":{"description":"Spaces per nesting level.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# H1\n\n## A\n\n## B"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"toc":"- [A](#a)\n- [B](#b)\n","headingCount":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/generate/slugs":{"post":{"operationId":"generate_slugs","summary":"Generate slugs","description":"Apply the same slugify algorithm that powers `/api/v1/render` heading anchors and GitHub's heading ids. Duplicate inputs get `-1`, `-2` suffixes so the slugs stay stable.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-generate-slugs","tags":["Generate"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"headings":{"description":"Heading titles. Max 1000 entries.","type":"string"}},"required":["headings"]},"example":{"headings":["Hello world","Hello world"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"slugs":[{"input":"Hello world","slug":"hello-world"},{"input":"Hello world","slug":"hello-world-1"}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/audit/headings":{"post":{"operationId":"audit_headings","summary":"Audit headings","description":"Find skipped heading levels (e.g. h2 → h4) and multiple H1s. Each issue points to a specific line with a severity tag so editors can surface them inline.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-audit-headings","tags":["Audit"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# A\n\n### Skipped"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"issues":[{"line":3,"severity":"warning","message":"Heading jumps from h1 to h3 (skipped level)."}],"count":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/audit/gfm":{"post":{"operationId":"audit_gfm","summary":"Audit GFM compliance","description":"Runs a quick GitHub Flavored Markdown checklist: single H1, fenced code blocks have a language tag, no empty link labels, images have alt text, pipe tables parse cleanly.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-audit-gfm","tags":["Audit"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# A\n\n```\necho hi\n```"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"items":[{"id":"h1","label":"Single H1 (recommended)","ok":true,"detail":"One H1."},{"id":"fence-lang","label":"Fenced code blocks specify a language when possible","ok":false,"detail":"At least one ``` fence lacks a language tag."}],"passed":1,"total":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/audit/readme-score":{"post":{"operationId":"audit_readme_score","summary":"README health score","description":"Composite health score for a README (or any markdown doc), combining heading hierarchy, GFM compliance, image alt text, link integrity, and open task ratio. Returns a 0–100 score, a letter grade, per-section breakdown, and an actionable issue list.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-audit-readme-score","tags":["Audit"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# Project\n\n## Intro\n\nHi."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"score":82,"grade":"B","sections":[{"id":"headings","label":"Heading hierarchy","passed":1,"total":1,"weight":20,"detail":"Outline is consistent."}],"issues":[]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/transform/typography":{"post":{"operationId":"transform_typography","summary":"Typography transforms","description":"Apply opt-in typography fixes: smart quotes ↔ straight, em-dashes ↔ double hyphens, ellipsis ↔ three dots, non-breaking space → space, zero-width-space strip. Code fences and inline code stay untouched.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-transform-typography","tags":["Transform"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"transforms":{"description":"List of transforms to apply.","type":"string"}},"required":["markdown","transforms"]},"example":{"markdown":"It's “great” — really…","transforms":["smart-quotes-to-straight","em-dash-to-double-hyphen","ellipsis-to-three-dots"]}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"text":"It's \"great\" -- really...","replacements":5}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/transform/redact":{"post":{"operationId":"transform_redact","summary":"Redact secrets","description":"Heuristic redaction of common sensitive patterns. Each category is opt-in: emails, IPv4, bearer tokens, AWS access keys, Stripe secret keys, GitHub tokens, JWTs, UUIDs, phone numbers, credit card numbers. Counts per category are returned.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-transform-redact","tags":["Transform"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"categories":{"description":"Categories to redact. Defaults to common secret patterns.","type":"string"}},"required":["markdown"]},"example":{"markdown":"Contact: ada@example.com (Bearer abc123abc123)"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"text":"Contact: [REDACTED:email] ([REDACTED:bearer])","replacements":2,"perCategory":{"email":1,"bearer":1,"ipv4":0,"aws-key":0,"stripe-secret":0,"github-token":0,"jwt":0,"uuid":0,"phone":0,"credit-card":0}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/transform/normalize-lists":{"post":{"operationId":"transform_normalize_lists","summary":"Normalize list markers","description":"Rewrite every unordered list marker (`*`, `+`) to `-` outside fenced code blocks. Indentation, nesting, and task-list checkboxes are preserved.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-transform-normalize-lists","tags":["Transform"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"}},"required":["markdown"]},"example":{"markdown":"* one\n* two"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"markdown":"- one\n- two","changed":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/transform/callout":{"post":{"operationId":"transform_callout","summary":"Build a callout / admonition","description":"Generate a callout block in the exact syntax your target tool expects. Avoids the headache of remembering whether MkDocs uses `!!!`, Docusaurus uses `:::`, or GitHub uses `> [!NOTE]`.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-transform-callout","tags":["Transform"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"style":{"description":"Target syntax.","type":"string","enum":["github","docusaurus","mkdocs","obsidian"]},"kind":{"description":"Callout type.","type":"string","enum":["note","tip","important","warning","caution"]},"title":{"description":"Optional callout title.","type":"string"},"body":{"description":"Body content.","type":"string"}},"required":["style","kind","body"]},"example":{"style":"github","kind":"note","title":"Heads up","body":"Read this."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"markdown":"> [!NOTE]\n> **Heads up**\n>\n> Read this.\n"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/diff":{"post":{"operationId":"diff","summary":"Diff markdown","description":"Line-by-line diff between two markdown documents. Each entry is tagged `added`, `removed`, or `unchanged` — ready for inline review UIs, content-review tools, and AI editing feedback loops.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-diff","tags":["Diff"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"left":{"description":"Original markdown.","type":"string"},"right":{"description":"Updated markdown.","type":"string"}},"required":["left","right"]},"example":{"left":"Hello world\n","right":"Hello there\n"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"diff":[{"type":"removed","value":"Hello world"},{"type":"added","value":"Hello there"}],"added":1,"removed":1,"unchanged":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/reading-time":{"post":{"operationId":"reading_time","summary":"Reading time","description":"Estimate reading time more honestly than 'words ÷ 200'. Prose runs at a configurable WPM (default 200); images add a fixed scan-time (default 12s); code lines add a fixed parse-time (default 2s). All three knobs are tunable.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-reading-time","tags":["Metrics"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"wpm":{"description":"Words per minute. Default 200.","type":"number"},"imageSeconds":{"description":"Seconds per image. Default 12.","type":"number"},"codeLineSeconds":{"description":"Seconds per code line. Default 2.","type":"number"}},"required":["markdown"]},"example":{"markdown":"# Hello\n\nA short paragraph."}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"words":4,"imageSeconds":0,"codeLines":0,"codeSeconds":0,"totalSeconds":1,"totalMinutes":1,"formatted":"1 sec read"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/split/sections":{"post":{"operationId":"split_sections","summary":"Split into sections","description":"Split a document into sections — either every heading (default) or only at a specific heading level. Each section comes back with its level, title, raw source, and starting line. Useful for LLM context chunking, multi-page site generation, or doc indexes.\n\nDocumentation: https://trymarkdownviewer.com/docs/api-split-sections","tags":["Diff"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"description":"Markdown source.","type":"string"},"byLevel":{"description":"When set, only split on headings of this level.","type":"string"}},"required":["markdown"]},"example":{"markdown":"# A\nfirst\n\n## B\nsecond"}}}},"responses":{"200":{"description":"Successful response.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"sections":[{"id":"s-0-a","level":1,"title":"A","raw":"# A\nfirst","line":1},{"id":"s-1-b","level":2,"title":"B","raw":"## B\nsecond","line":4}],"count":2}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"504":{"$ref":"#/components/responses/Timeout"}}}},"/api/v1/health":{"get":{"operationId":"health","summary":"Health check","description":"Public, unauthenticated heartbeat for uptime monitoring. Returns API version and dependency status.","tags":["Platform"],"security":[],"responses":{"200":{"description":"Service is healthy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope"},"example":{"data":{"status":"ok","version":"v1","time":"2026-01-15T12:00:00.000Z","services":{"rateLimit":"configured"}}}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key issued from the dashboard. Format: `mdv_live_*` (production) or `mdv_test_*` (self-hosted dev)."}},"schemas":{"SuccessEnvelope":{"type":"object","required":["data"],"properties":{"data":{"type":"object","description":"Endpoint-specific payload.","additionalProperties":true}}},"ErrorEnvelope":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code.","enum":["bad_request","unauthorized","forbidden","not_found","method_not_allowed","payload_too_large","unsupported_media_type","rate_limited","quota_exceeded","timeout","internal_error"]},"message":{"type":"string","description":"Human-readable error message."},"details":{"type":"object","description":"Optional structured details (e.g. field validation errors).","additionalProperties":true}}}}}},"responses":{"BadRequest":{"description":"Invalid request body or validation failure.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"bad_request","message":"Invalid request body.","details":{"fieldErrors":{"markdown":["Required"]}}}}}}},"Unauthorized":{"description":"Missing, malformed, revoked, or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"unauthorized","message":"Missing or invalid API key."}}}}},"PayloadTooLarge":{"description":"Request body exceeds the per-endpoint size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"payload_too_large","message":"Payload too large."}}}}},"UnsupportedMediaType":{"description":"Content-Type must be application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"unsupported_media_type","message":"Content-Type must be application/json."}}}}},"RateLimited":{"description":"Burst rate limit or plan quota exceeded.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Maximum requests allowed in the current quota window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in the current quota window."},"X-RateLimit-Reset":{"schema":{"type":"integer","format":"int64"},"description":"Unix timestamp when the quota window resets."},"X-RateLimit-Window":{"schema":{"type":"string","enum":["day","month"]},"description":"Quota window for the authenticated plan."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"rate_limited","message":"Too many requests."}}}}},"InternalError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"internal_error","message":"Internal server error."}}}}},"Timeout":{"description":"Processing exceeded the per-request CPU budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"timeout","message":"Request timed out."}}}}}}}}