Fetch URL as Markdown API
Convert any web page into clean, LLM-ready Markdown. Fetches over plain HTTP with browser headers (retrying once through a residential or datacenter proxy when the origin serves a bot wall), removes boilerplate with Mozilla Readability, and converts with GitHub-flavored Markdown tables, lists and code blocks. Article mode is verified against a whole-page conversion and downgrades itself when Readability strips too much, so you are never handed a gutted page. Returns the markdown plus title, byline, language, excerpt, the extracted link list, the final URL after redirects, and which transport served the body. No browser is used, so a client-rendered page is reported as an error rather than as empty content.
Part of: URL to Markdown API
How to call it
Send one POST to api.upapi.io/fetch-markdown.post with your key in the X-Api-Key header and the parameters below as a JSON body. Each call spends 3 weighted units of your monthly quota. The operation times out after 25 seconds. Identical requests are served from cache for 300 seconds, unbilled.
POST https://api.upapi.io/fetch-markdown.post
Fetch URL as Markdown API reference
Request parameters
- url
- stringrequired — Absolute http(s) URL of the page to convert (e.g. https://en.wikipedia.org/wiki/Markdown). Private, loopback and link-local destinations are refused.
- mode
- enum — article = Mozilla Readability main-content extraction, verified against the whole page and auto-downgraded when it strips too much; full = the whole body with nav/footer/aside/form removed (e.g. article).
- maxChars
- integer — Maximum characters of markdown to return (e.g. 100000). Output is cut at the nearest paragraph/line boundary and
truncatedis set. - timeoutMs
- integer — Total network budget in milliseconds across the direct attempt and the one proxied retry (e.g. 20000). Capped below the 28s API-gateway edge timeout.
- includeLinks
- boolean — Keep inline [text](url) links in the markdown and return the extracted link list (e.g. true). false unwraps every anchor to plain text.
- includeImages
- boolean — Keep  image references in the markdown (e.g. false). Images are dropped by default because they cost tokens and rarely help an LLM.
Response fields
- lang
- objectrequired — Language tag from <html lang> (e.g. "en"); null if absent.
- links
- array — Absolute http(s) links found in the extracted content, capped at 500. Present only when includeLinks is true; reflects the extracted document, which may be longer than a truncated markdown body.
- links[].href
- stringrequired
- links[].text
- stringrequired
- title
- stringrequired — Page/article title, or an empty string if none was found.
- byline
- objectrequired — Author line, when Readability or a meta tag exposes one; null otherwise.
- excerpt
- objectrequired — Short summary from Readability or the meta description; null if absent.
- finalUrl
- stringrequired — URL actually fetched, after following redirects.
- markdown
- stringrequired — The converted document. Prefixed with the page title as an H1 when the extracted content does not already start with a heading.
- charCount
- integerrequired — Length of the returned markdown.
- extractor
- enumrequired — Which stage produced the markdown. In article mode this reads "full-dom" when Readability failed the content-density check.
- fetchedAt
- stringrequired — ISO-8601 timestamp of the fetch.
- truncated
- booleanrequired — True when the markdown was cut to fit maxChars.
- httpStatus
- integerrequired — HTTP status of the response that produced the markdown.
- fetchedWith
- enumrequired — Transport that produced the returned body: direct = straight from the worker; datacenter/residential = the proxy-pool tier used for the retry.
Example request and response
The example response is generated from this operation’s published output schema — it shows the shape and field names, not values from a recorded call.
{
"url": "https://en.wikipedia.org/wiki/Markdown",
"mode": "article",
"maxChars": 100000,
"timeoutMs": 20000,
"includeLinks": true,
"includeImages": false
}{
"lang": "en",
"links": [
{
"href": "example",
"text": "Hello, world"
}
],
"title": "Alan Turing",
"byline": {},
"excerpt": {},
"finalUrl": "example",
"markdown": "example",
"charCount": 1,
"extractor": "readability",
"fetchedAt": "example",
"truncated": false,
"httpStatus": 1,
"fetchedWith": "direct"
}Code snippets
cURL
curl -X POST https://api.upapi.io/fetch-markdown.post \
-H 'Content-Type: application/json' \
-H 'x-api-key: YOUR_API_KEY' \
-d '{ "url": "https://en.wikipedia.org/wiki/Markdown", "mode": "article", "maxChars": 100000, "timeoutMs": 20000, "includeLinks": true, "includeImages": false }'JavaScript
const response = await fetch('https://api.upapi.io/fetch-markdown.post', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY',
},
body: JSON.stringify({
"url": "https://en.wikipedia.org/wiki/Markdown",
"mode": "article",
"maxChars": 100000,
"timeoutMs": 20000,
"includeLinks": true,
"includeImages": false
}),
});
const data = await response.json();
console.log(data);Python
import requests
response = requests.post(
'https://api.upapi.io/fetch-markdown.post',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY',
},
json={
"url": "https://en.wikipedia.org/wiki/Markdown",
"mode": "article",
"maxChars": 100000,
"timeoutMs": 20000,
"includeLinks": True,
"includeImages": False
},
)
print(response.json())Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
payload := []byte(`{ "url": "https://en.wikipedia.org/wiki/Markdown", "mode": "article", "maxChars": 100000, "timeoutMs": 20000, "includeLinks": true, "includeImages": false }`)
req, _ := http.NewRequest("POST", "https://api.upapi.io/fetch-markdown.post", bytes.NewBuffer(payload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-api-key", "YOUR_API_KEY")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]any
json.Unmarshal(body, &result)
fmt.Println(result)
}PHP
<?php
$payload = json_encode([
'url' => 'https://en.wikipedia.org/wiki/Markdown',
'mode' => 'article',
'maxChars' => 100000,
'timeoutMs' => 20000,
'includeLinks' => true,
'includeImages' => false,
]);
$ch = curl_init('https://api.upapi.io/fetch-markdown.post');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: YOUR_API_KEY',
],
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
var_dump($data);Ruby
require 'net/http'
require 'uri'
require 'json'
uri = URI('https://api.upapi.io/fetch-markdown.post')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme == 'https'
request = Net::HTTP::Post.new(uri.path)
request['Content-Type'] = 'application/json'
request['x-api-key'] = 'YOUR_API_KEY'
request.body = { "url": "https://en.wikipedia.org/wiki/Markdown", "mode": "article", "maxChars": 100000, "timeoutMs": 20000, "includeLinks": true, "includeImages": false }.to_json
response = http.request(request)
puts JSON.parse(response.body)Java
import okhttp3.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
OkHttpClient client = new OkHttpClient();
ObjectMapper mapper = new ObjectMapper();
String json = "{ \"url\": \"https://en.wikipedia.org/wiki/Markdown\", \"mode\": \"article\", \"maxChars\": 100000, \"timeoutMs\": 20000, \"includeLinks\": true, \"includeImages\": false }";
RequestBody body = RequestBody.create(json, MediaType.get("application/json"));
Request request = new Request.Builder()
.url("https://api.upapi.io/fetch-markdown.post")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("x-api-key", "YOUR_API_KEY")
.build();
try (Response response = client.newCall(request).execute()) {
Map<?, ?> result = mapper.readValue(response.body().string(), Map.class);
System.out.println(result);
}C#
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key", "YOUR_API_KEY");
var payload = JsonSerializer.Deserialize<object>("{ \"url\": \"https://en.wikipedia.org/wiki/Markdown\", \"mode\": \"article\", \"maxChars\": 100000, \"timeoutMs\": 20000, \"includeLinks\": true, \"includeImages\": false }");
var response = await client.PostAsJsonAsync("https://api.upapi.io/fetch-markdown.post", payload);
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(result);Frequently asked questions
How much does the Fetch URL as Markdown API cost per call?
Each call spends 3 weighted units of your plan's monthly quota. Full pricing is at https://upapi.io/pricing.
How do I authenticate to the Fetch URL as Markdown API?
Send your key in the X-Api-Key header. A free guest key is available without creating an account.
Are Fetch URL as Markdown API responses cached?
Yes — identical requests are served from cache for 300 seconds, and a cache hit is not billed.