# 2md.chat > Turns a PUBLIC share link of an AI conversation, or a public Claude artifact, into Markdown. > No key, no login, no rate card. Every answer is UTF-8 and may be fetched from any origin (CORS *). The one thing to remember: put `https://2md.chat/` in front of the share link and fetch it. GET https://2md.chat/https://chatgpt.com/share/ -> 200 text/markdown ## Supported links - ChatGPT: https://chatgpt.com/share/ - Claude: https://claude.ai/share/ - Claude artifact: https://claude.ai/artifact/ or https://claude.ai/public/artifacts/ - Gemini: https://gemini.google.com/share/ or https://g.co/gemini/share/ - Grok: https://grok.com/share/ - DeepSeek: https://chat.deepseek.com/share/ - Kimi: https://www.kimi.com/share/ - Qwen: https://chat.qwen.ai/s/ - GLM (Z.ai): https://chat.z.ai/s/ - Mistral Le Chat: https://chat.mistral.ai/chat/ - Perplexity: https://www.perplexity.ai/search/ - Meta AI: https://www.meta.ai/share/c/ Only public links work. A private or deleted link answers with an error, never with partial content. ## Routes GET / e.g. GET /https://chatgpt.com/share/ The Markdown itself (text/markdown). Nothing else - no HTML, no interface. Send "Accept: application/json" to get the JSON result instead (see /api/convert). Flags in the query string (any other query parameter belongs to the share link): ?frontmatter=1 YAML frontmatter (title, source, provider, exported) instead of the header lines ?bare=1 content only, no title or header Errors are text/plain, "Error: ()", with a 4xx status. GET /api/convert?url=[&frontmatter=1|&bare=1] POST /api/convert body: {"url": "", "frontmatter": true | "bare": true} 200: {"ok": true, "provider", "title", "sourceUrl", "markdown", "filename", "messageCount"} 4xx: {"ok": false, "error": "", "code": ""} OpenAPI: /openapi.json POST /mcp MCP server (Streamable HTTP, stateless, JSON answers). One tool: convert_share_link {url, header?}. Claude Code: claude mcp add --transport http 2md https://2md.chat/mcp Any client: {"mcpServers": {"2md": {"type": "http", "url": "https://2md.chat/mcp"}}} POST /api/share body: {"markdown", "filename", "title", "sourceUrl", "maxViews"?, "expiresInSeconds"?} Stores Markdown and returns {"url": "/md/", "rawUrl": "/md//raw", "downloadUrl": "/md//download"}. Links expire after 24 hours by default. GET /md/ the stored Markdown for any client that does not ask for text/html; browsers get the interface GET /md//raw always the Markdown GET /md//download the same, as an attachment GET / this file for agents and curl; the web interface for browsers; /?url= pre-fills it ## Output shape # Source: <share-url> Provider: <name> Exported: <ISO time> --- ## User <message> ## Assistant <message, Markdown kept as written: code fences, tables, links> Thinking/reasoning blocks are left out. Artifacts come out as one document: scripts are run and "show more" is expanded, so long tables are complete. ## Error codes unsupported_provider the link is not one of the sources above invalid_url not a URL *_not_public the share or artifact is private *_not_found deleted or never existed *_http_error the source answered with an error (shown as 424) *_cloudflare_challenge the source asked for a browser check this server could not pass ## Example curl https://2md.chat/https://claude.ai/artifact/<id>?frontmatter=1