{"service":"dupe-markdown","version":"0.3.0","status":"ok","description":"Internal URL-to-Markdown conversion service. Three-tier cascade: Content Negotiation → Workers AI → Browser Rendering.","auth":"Authorization: Bearer <API_KEY>","endpoints":{"convert":{"description":"Convert a URL to markdown","formats":["GET /https://example.com","GET /?url=https://example.com","POST / {\"url\":\"https://example.com\"}"]},"health":{"description":"This endpoint. GET / without a ?url param. No auth required."}},"parameters":{"url":{"type":"string","required":true,"description":"The URL to convert to markdown"},"method":{"type":"string","default":"auto","options":["auto","ai","browser"],"description":"auto = try all tiers, ai = Workers AI only, browser = headless Chrome"},"mode":{"type":"string","default":"article","options":["article","full"],"description":"article = main content only (Readability + cleanup), full = everything"},"extract":{"type":"string","default":"none","options":["none","llm","review"],"description":"none = heuristic cleanup, llm = Groq Llama 3.3 70B extraction (adds latency), review = review extraction (requires product_name)"},"extract_model":{"type":"string","default":"groq:llama-3.3-70b-versatile","description":"LLM model for extraction. Format: groq:<model-id> or bedrock:<model-id>","examples":["groq:llama-3.1-8b-instant","groq:llama-3.3-70b-versatile","bedrock:us.anthropic.claude-haiku-4-5-20250929-v1:0"]},"extract_context":{"type":"string","description":"Additional context injected into extraction prompt (e.g. shopper archetype brief)"},"product_name":{"type":"string","description":"Product name for extract=review mode (required when extract=review)"},"product_brand":{"type":"string","description":"Product brand for extract=review mode"},"retain_images":{"type":"boolean","default":false,"description":"Keep ![alt](url) image references in output"},"no_cache":{"type":"boolean","default":false,"description":"Skip cache read and force fresh conversion. Also supports Cache-Control: no-cache header. Fresh result is still written to cache."},"min_tokens":{"type":"integer","default":200,"description":"Minimum token count to cache a result. Results below this threshold are returned but not cached. Set to 0 to cache everything."}},"response_headers":{"x-markdown-tokens":"Estimated LLM token count (~4 chars/token)","x-conversion-method":"content-negotiation | workers-ai | browser-rendering","x-conversion-latency-ms":"Conversion time in milliseconds","x-content-mode":"article | full","x-cache":"HIT | MISS | NEGATIVE-HIT","x-article-title":"Article title (when available)","x-article-byline":"Author byline (when available)"},"caching":{"positive":{"ttl":"3600s","storage":"Cloudflare edge (nearest POP)","quality_gate":"Results under 200 tokens are not cached (override with ?min_tokens=N)"},"negative":{"description":"Failed conversions are cached briefly to avoid retrying broken URLs","client_errors_ttl":"5 minutes (4xx)","server_errors_ttl":"2 minutes (5xx/timeouts)"},"bypass":"?no_cache=true or Cache-Control: no-cache header"},"errors":{"400":"INVALID_REQUEST | INVALID_URL","401":"UNAUTHORIZED","502":"CONVERSION_FAILED (all tiers failed)"},"proxy":{"description":"Optional HTTP forward proxy for bot-detection bypass. Direct fetch is tried first; if blocked (403/429/challenge page), retries through the proxy.","parameter":"proxy_url","format":"Standard proxy URL: http://user:pass@host:port","compatible_with":"Residential proxy services (Thor/Thordata, Bright Data, Oxylabs, etc.)","response_header":"X-Proxy-Used: true/false"}}