URL zu Markdown API#
Der Endpoint POST /v1/convert/url-to-markdown konvertiert jede öffentlich zugängliche Webseite in sauberes GitHub-Flavored Markdown mit einem YAML-Frontmatter-Metadatenblock. Jede Seite wird in einem echten Browser gerendert, durch einen Readability-Extraktor geschickt, der Boilerplate entfernt (Navigation, Footer, Asides, Scripts, Formulare, Buttons), und anschließend zu Markdown serialisiert. Dabei werden Links normalisiert, Codeblöcke eingerahmt und relative URLs zu absoluten aufgelöst. Genau das, was LLM-Ingestion- und RAG-Pipelines brauchen, statt rohem HTML. Konvertierungen laufen synchron oder asynchron im Batch, und die Ergebnisse werden als rohe Markdown-Bytes oder als vorsignierte Download-URL zurückgegeben.
Endpunkt#
POST /v1/convert/url-to-markdown
Content-Type: application/json
Ausgabeformat: Markdown (.md, UTF-8) mit einem YAML-Frontmatter-Block am Anfang der Datei, der Seiten-Metadaten enthält. Das Ausgabeformat ist nicht konfigurierbar. Es wird immer Markdown mit YAML-Frontmatter erzeugt.
Authentifizierung#
Dieser Endpunkt unterstützt sowohl Private-Key- als auch Public-Key-Authentifizierung.
Privater Schlüssel#
Gib deinen geheimen Schlüssel im X-API-Key-Header an. Verwende dies für Server-zu-Server-Aufrufe, bei denen der Schlüssel dem Client nie offengelegt wird.
X-API-Key: sk_your_private_key
Öffentlicher Schlüssel mit JWT#
Für die clientseitige Nutzung generierst du zuerst ein JWT-Token mit deinem öffentlichen Schlüssel und übergibst es dann als Bearer-Token.
Schritt 1 -- Token abrufen:
POST /v1/auth/token
X-API-Key: pk_your_public_key
Schritt 2 -- Token verwenden:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Anfrageparameter#
Parameter der obersten Ebene#
| Parameter | Type | Required | Default | Description | Plan Gating |
|---|---|---|---|---|---|
url |
string oder string[] |
Ja | -- | Ein einzelner URL-String oder ein Array von URLs, die konvertiert werden sollen. Mehrere URLs erfordern den Async-Modus. | -- |
async_mode |
boolean |
Nein | false |
Führt die Konvertierung asynchron aus. Gibt sofort eine batch_id zum Polling zurück. Erforderlich für Batch (mehrere URLs). |
Erfordert Async-Zugriff |
direct_download |
boolean |
Nein | false |
Gibt rohe Markdown-Bytes im Response-Body zurück statt einer JSON-Antwort mit vorsignierter URL. Bei öffentlichen Schlüsseln fest auf true gesetzt. Nicht kompatibel mit async_mode und mehreren URLs. |
-- |
output_format |
boolean |
Nein | false |
Bei true mit mehreren URLs werden alle Markdown-Ausgabedateien in ein einzelnes ZIP-Archiv gebündelt. Erfordert mehrere URLs. |
Erfordert Zugriff auf ZIP-Ausgabe |
output_filename |
string |
Nein | Automatisch generiert | Benutzerdefinierter Dateiname für die Ausgabedatei. Die Erweiterung .md wird automatisch hinzugefügt. Standardformat: {domain}_{timestamp}.md. |
-- |
job_id |
string |
Nein | -- | Vom Client bereitgestellte Job-ID zur Timeout-Wiederherstellung. Nur öffentliche Schlüssel. Wenn eine synchrone Konvertierung die Timeout-Grenzen des Reverse-Proxys überschreitet, kann der Client GET /v1/convert/status/{job_id} abfragen, um das Ergebnis zu erhalten. Wird bei privaten Schlüsseln ignoriert. |
-- |
notification_email |
string |
Nein | E-Mail-Adresse des Projektinhabers | E-Mail-Adresse, die benachrichtigt wird, wenn ein Async-Job abgeschlossen ist. Nur private Schlüssel. | -- |
callback_url |
string |
Nein | -- | Webhook-URL, die eine POST-Anfrage erhält, wenn die Konvertierung abgeschlossen ist. Nur private Schlüssel. | Erfordert Webhook-Zugriff |
Browser- und Rendering-Parameter#
| Parameter | Type | Required | Default | Description | Plan Gating |
|---|---|---|---|---|---|
viewport_width |
integer |
Nein | 1920 |
Breite des Browser-Viewports in Pixeln. Beeinflusst responsiven Content und welche Layout-Variante vor der Extraktion erfasst wird. | -- |
viewport_height |
integer |
Nein | 1080 |
Höhe des Browser-Viewports in Pixeln. Dient als Referenz für Rendering und die Berechnung von Viewport-Einheiten. | -- |
load_media |
boolean |
Nein | true |
Wartet, bis alle Bilder und Videos vollständig geladen sind, bevor die Extraktion beginnt. Bei false ist die Extraktion schneller, aber lazy-geladene Bilder können im Markdown-Output Platzhalter-Werte bei src haben. |
-- |
enable_scroll |
boolean |
Nein | true |
Scrollt die Seite von oben nach unten, um Lazy-Loading-Content auszulösen (IntersectionObserver-basierte Loader). | -- |
handle_sticky_header |
boolean |
Nein | true |
Erkennt sticky/fixed Header und scrollt vor der Extraktion nach oben, sodass die Content-Reihenfolge korrekt erhalten bleibt. | -- |
handle_cookies |
boolean |
Nein | true |
Schließt Cookie-Consent-Banner (OneTrust, Cookiebot, Didomi, Usercentrics und generische Banner) vor der Extraktion automatisch. | -- |
wait_for_images |
boolean |
Nein | true |
Wartet, bis alle <img>-Elemente fertig geladen sind (5-Sekunden-Timeout pro Bild), damit alt-Text und finale src-Werte korrekt erfasst werden. |
-- |
wait_for_selector |
string |
Nein | null |
CSS-Selektor, auf den vor der Extraktion gewartet wird. Gibt 422 zurück, wenn er nicht innerhalb von wait_for_selector_timeout erscheint. Nützlich für SPAs, die Inhalte nach dem Laden hydrieren. |
-- |
wait_for_selector_timeout |
integer |
Nein | 10000 |
Millisekunden, die auf wait_for_selector gewartet wird (maximal 60000). |
-- |
block_ads |
boolean |
Nein | false |
Bricht Anfragen an bekannte Werbe-/Tracker-Domains ab, sodass diese nie geladen werden oder die Extraktion verlangsamen. | -- |
block_media |
boolean |
Nein | false |
Bricht Bild- und Audio-/Videoanfragen vollständig ab, für ein schnelleres, leichteres Rendering. Anders als load_media (das nur das Warten steuert), verhindert dies das Herunterladen von Medien vollständig. |
-- |
Authentifizierung und benutzerdefinierte Anfragen#
| Parameter | Type | Required | Default | Description | Plan Gating |
|---|---|---|---|---|---|
auth |
object |
Nein | null |
HTTP-Basic-Auth-Zugangsdaten für die Ziel-URL. Format: {"username": "...", "password": "..."}. Kann nicht zusammen mit einem benutzerdefinierten Authorization-Header verwendet werden. |
Erfordert Basic-Auth-Zugriff |
cookies |
array |
Nein | null |
Array von Cookie-Objekten, die vor der Navigation injiziert werden. Maximal 50 Cookies. Jedes Cookie muss name, value sowie entweder domain oder url enthalten. |
Erfordert Basic-Auth-Zugriff |
headers |
object |
Nein | null |
Dictionary mit benutzerdefinierten HTTP-Headern, die mit jeder Anfrage an die Ziel-URL gesendet werden. Maximal 20 Header. Blockierte Header: host, content-length, transfer-encoding, connection, upgrade, te, trailer. |
Erfordert Basic-Auth-Zugriff |
single_page und pdf_options aus dem url-to-pdf-Endpunkt werden zur Wahrung der Request-Struktur akzeptiert, haben aber keine Auswirkung auf die Markdown-Ausgabe. Markdown kennt kein Konzept von Seiten, Rändern oder Ausrichtung.
Cookie-Objekt-Schema#
Jedes Element im cookies-Array muss dieser Struktur folgen:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string |
Ja | -- | Cookie-Name. |
value |
string |
Ja | -- | Cookie-Wert. |
domain |
string |
Bedingt | -- | Cookie-Domain. Entweder domain oder url muss angegeben werden. |
url |
string |
Bedingt | -- | URL, mit der das Cookie verknüpft wird. Entweder domain oder url muss angegeben werden. |
path |
string |
Nein | "/" |
Cookie-Pfad. Standardmäßig "/", wenn domain gesetzt ist. |
Antwort#
Synchron mit Direct Download (direct_download=true)#
Privater Schlüssel -- gibt rohe Markdown-Bytes zurück:
HTTP 200 OK
Content-Type: text/markdown; charset=utf-8
Content-Disposition: inline; filename="example_20260421_123456789.md"
X-Object-Key: env/files/{project_id}/url-to-markdown/example_20260421_123456789.md
X-File-Size: 8421
X-Conversion-Time: 6.3
X-Filename: example_20260421_123456789.md
(UTF-8 Markdown with YAML frontmatter)
Öffentlicher Schlüssel -- gibt JSON mit einer vorsignierten URL zurück:
{
"presigned_url": "https://spaces.example.com/...",
"object_key": "env/files/{project_id}/url-to-markdown/example_20260421_123456789.md",
"filename": "example_20260421_123456789.md",
"file_size": 8421,
"conversion_time_seconds": 6.3,
"job_id": "client-provided-id"
}
Synchron ohne Direct Download (direct_download=false)#
Nur mit privaten Schlüsseln verfügbar.
{
"presigned_url": "https://spaces.example.com/...",
"object_key": "env/files/{project_id}/url-to-markdown/example_20260421_123456789.md",
"filename": "example_20260421_123456789.md",
"file_size": 8421,
"conversion_time_seconds": 6.3
}
Asynchroner Modus#
Gibt sofort eine batch_id zum Polling zurück.
HTTP 202 Accepted
{
"status": "processing",
"batch_id": "550e8400-e29b-41d4-a716-446655440000",
"url_count": 5,
"output_format": "individual"
}
Bei output_format=true (ZIP-Bündelung):
{
"status": "processing",
"batch_id": "550e8400-e29b-41d4-a716-446655440000",
"url_count": 5,
"output_format": "zip"
}
Job-Status-Polling (nur öffentliche Schlüssel)#
Für die Timeout-Wiederherstellung bei öffentlichem Schlüssel:
GET /v1/convert/status/{job_id}
Authorization: Bearer <jwt_token>
| Status | Response |
|---|---|
| Verarbeitung | {"status": "processing"} |
| Erfolg | {"status": "success", "presigned_url": "...", "object_key": "..."} |
| Fehlgeschlagen | {"status": "failed", "error": "..."} |
Batch-Status-Polling (nur private Schlüssel)#
Frage bei asynchronen Batch-Jobs mit der batch_id aus der 202-Antwort ab:
GET /v1/convert/batch/{batch_id}
X-API-Key: sk_your_private_key
Gibt aggregierten Status, Status pro URL sowie vorsignierte Download-URLs zurück. Siehe Batch-Status-Polling für das vollständige Response-Schema.
Webhook-Callback-Payload#
Wenn eine callback_url angegeben ist, sendet EnConvert nach Abschluss eine POST-Anfrage an diese URL.
Einzel-URL-Job:
{
"job_id": "activity_id",
"status": "success",
"batch_id": "...",
"gcs_uri": "object_key",
"filename": "example_20260421_123456789.md",
"file_size": 8421
}
Batch-Job:
{
"job_id": "activity_id",
"status": "success",
"batch_id": "...",
"total_tasks": 10,
"successful_tasks": 8,
"failed_tasks": 2,
"tasks": [
{"url": "https://example.com/page1", "status": "success", "filename": "page1.md"},
{"url": "https://example.com/page2", "status": "failed", "filename": null}
]
}
Ausgabeformat#
Jede Markdown-Datei beginnt mit einem YAML-Frontmatter-Block, der Seiten-Metadaten enthält, gefolgt vom extrahierten Artikeltext.
---
url: https://example.com/articles/my-post
title: My Post Title
description: A short summary from the meta description or og:description tag.
links:
- url: https://example.com/related
text: Related article
- url: https://example.com/about
text: About the author
images:
- url: https://example.com/hero.jpg
alt: Hero image alt text
- url: https://example.com/diagram.png
alt: Architecture diagram
---
# My Post Title
Opening paragraph of the article body, converted to GitHub-Flavored Markdown...
## A Section Heading
- List item one
- List item two
\`\`\`python
def example():
return "code blocks are fenced with language hints"
\`\`\`
[A link in the body](https://example.com/linked-page)

Frontmatter-Felder#
| Field | Type | Description |
|---|---|---|
url |
string |
Die finale URL nach Weiterleitungen (nicht immer die URL, die du gesendet hast). |
title |
string |
Der Seitentitel aus <title>, mit Fallback auf den von Readability erkannten Kurztitel. |
description |
string |
Der Wert von <meta name="description">, mit Fallback auf <meta property="og:description">. |
links |
array |
Jedes auf der Seite gefundene <a href>, mit absoluten URLs und sichtbarem Ankertext. |
images |
array |
Jedes auf der Seite gefundene <img src>, mit absoluten URLs und alt-Text. |
Markdown-Konventionen#
- Überschriftenstil: ATX (
#,##,###) - Listenpunkte:
- - Hervorhebung:
*bold*,*italic*, mit escaptem*und_in literalem Text - Weiche Zeilenumbrüche: zwei nachgestellte Leerzeichen (im Output erhalten)
- Codeblöcke: eingerahmt (
```) mit Sprachhinweisen, erkannt ausclass="language-xxx",class="lang-xxx",class="highlight-source-xxx",data-langunddata-language - Links:
[text](url), wenn Ankertext vorhanden ist; Autolink-Form<url>, wenn der Anker leer ist; reine Anker-Links (#foo) undjavascript:-Links werden zu reinem Text entpackt - Bilder:
, wobeititleerhalten bleibt, falls vorhanden, mit Fallback aufdata-src, wennsrcfehlt (lazy-geladene Bilder) - Horizontale Linien:
---
Funktionen#
Saubere Content-Extraktion#
EnConvert verwendet den Readability-Algorithmus (dieselbe Bibliothek, die auch die Firefox Reader View antreibt), um den Hauptartikel-Content vom Rest der Seite zu isolieren, und wendet anschließend einen zweiten Nachbearbeitungsschritt an, um sauberes Markdown zu erzeugen.
Vor der Konvertierung entfernt:
- Navigation (
<nav>), Footer (<footer>), Asides (<aside>) - Scripts (
<script>,<noscript>), Styles (<style>), iframes, Formulare, Buttons - Inline-SVG, Canvas- und Template-Elemente
style,class,idund alleon*-Event-Handler-Attribute
Erhalten bleiben:
- Überschriften, Absätze, Listen, Tabellen, Blockquotes, Codeblöcke
- Links mit ihrem
hrefund Ankertext (absolute URLs) - Bilder mit
alt,titleund absolutemsrc - Figures und Figcaptions (Inline-Bilder bleiben darin erhalten)
Sauberer Erfassungsmodus#
Vor der Extraktion wird die Seite in einem echten Browser gerendert und auf dieselbe Weise bereinigt wie bei url-to-pdf:
- Cookie-Consent-Banner -- Werden auf der Hauptseite und in iframes automatisch geschlossen (OneTrust, Cookiebot, Didomi, Usercentrics und generische Banner).
- Schließen von Modals und Popups -- Overlays werden per Escape-Taste, ARIA-Schließen-Buttons, klassenbasierten Schließen-Buttons und rollenbasierten Dialog-Buttons geschlossen.
- Scroll-Animation-Reveal -- Erzwingt die Sichtbarkeit von Elementen, die durch WOW.js, AOS, ScrollReveal, GSAP ScrollTrigger und generische Animationsklassen verborgen sind.
- Behandlung von Sticky-Headern -- Sticky/fixed Header werden erkannt und die Seite wird zurück nach oben gescrollt, sodass die Content-Reihenfolge erhalten bleibt.
Auflösung absoluter URLs#
Jedes relative href und src im extrahierten Artikel wird gegen die finale Seiten-URL (nach Weiterleitungen) aufgelöst, sodass der Markdown-Output immer absolute, klickbare Links enthält. Das hilft LLM-Ingestion-Pipelines, die sonst defekte relative Pfade sehen würden.
Reine Anker-Links (#section), javascript:-Links, mailto:- und tel:-Links werden nicht umgeschrieben. Reine Anker-Links und javascript:-Links werden zu reinem Text entpackt, da sie außerhalb der Originalseite keine Bedeutung haben.
Erkennung der Codeblock-Sprache#
Codeblöcke werden nach Möglichkeit mit einem erkannten Sprachhinweis eingerahmt:
<pre><code class="language-python">...</code></pre> → ```python
<pre data-lang="js">...</pre> → ```js
<pre><code class="highlight-source-shell">...</code></pre> → ```shell
Klassen, die language-*, lang-*, highlight-source-* und brush:* entsprechen, werden erkannt, ebenso die Attribute data-lang und data-language sowohl am <pre> als auch am verschachtelten <code>. Wird kein Hinweis gefunden, wird der Block ohne Sprachkennzeichnung eingerahmt.
HTTP Basic Auth#
Übergib auth mit username und password, um Seiten hinter HTTP Basic Authentication zu konvertieren.
{
"url": "https://staging.example.com/docs/article",
"auth": {
"username": "admin",
"password": "secret"
}
}
Cookie-Injection#
Injiziere bis zu 50 Cookies, bevor die Seite lädt. Nützlich zum Konvertieren von Mitglieder-exklusiven oder locale-spezifischen Artikelseiten.
{
"url": "https://example.com/members/post",
"cookies": [
{"name": "session_id", "value": "abc123", "domain": "example.com"},
{"name": "locale", "value": "en-US", "domain": "example.com"}
]
}
Benutzerdefinierte Header#
Sende bis zu 20 benutzerdefinierte HTTP-Header mit jeder Anfrage an die Zielseite.
{
"url": "https://example.com/api-docs",
"headers": {
"X-Custom-Token": "my-token-value",
"Accept-Language": "en-US"
}
}
Lazy-Loading von Bildern#
Wenn load_media und enable_scroll aktiviert sind (beide standardmäßig true), scrollt der Converter die Seite langsam, um Lazy-Loader auszulösen, und wartet dann, bis alle Bilder fertig geladen sind, bevor das finale HTML erfasst wird. So wird sichergestellt, dass data-src-Werte zu echten src-Werten hochgestuft wurden und die images-Liste im Frontmatter vollständig ist.
Setze load_media=false für eine schnellere Extraktion, wenn du nur den Textkörper benötigst. Platzhalter-Werte bei src können dann im Output verbleiben.
Weitere Rendering-Funktionen#
- Normalisierung von Viewport-Einheiten -- CSS-Viewport-Einheiten (
vh,svh,lvh,dvh) werden vor der Extraktion in feste Pixelwerte umgerechnet. - Stealth-Modus -- Maskierung des Browser-Fingerprints, um Bot-Erkennung auf geschützten Seiten zu vermeiden.
- Popup-Abfangen -- Schließt automatisch alle neuen Browser-Tabs oder Popups, die von der Seite ausgelöst werden.
- CSP-Bypass -- Behandelt Content-Security-Policy- und Trusted-Types-Beschränkungen, die die Seitenmanipulation sonst blockieren würden.
Abo-Plan-Einschränkungen#
| Feature | Founding | Indie | Studio | Enterprise |
|---|---|---|---|---|
| Basiskonvertierung (einzelne URL, synchron) | Ja | Ja | Ja | Ja |
| Viewport- und Rendering-Optionen | Ja | Ja | Ja | Ja |
| Async-Modus | Nein | Ja | Ja | Ja |
| Batch-Verarbeitung (mehrere URLs) | Nein | Ja | Ja | Ja |
| ZIP-Ausgabebündelung | Nein | Nein | Ja | Ja |
| Webhook-Callbacks | Nein | Nein | Ja | Ja |
| HTTP Basic Auth | Nein | Ja | Ja | Ja |
| Cookie-Injection | Nein | Ja | Ja | Ja |
| Benutzerdefinierte Header | Nein | Ja | Ja | Ja |
| Monatliche Konvertierungen | 100 | Planabhängig | Planabhängig | Unbegrenzt |
| Batch-Größenlimit | 0 | Planabhängig | Planabhängig | Unbegrenzt |
| Dateiaufbewahrung | 1 Stunde | Planabhängig | Planabhängig | Planabhängig |
Async-Modus#
Der asynchrone Modus ist nützlich für lang laufende Konvertierungen oder bei der Konvertierung mehrerer URLs.
So funktioniert's#
- Sende eine Anfrage mit
async_mode=true(oder übergib mehrere URLs, wodurch Async automatisch aktiviert wird). - Die API gibt sofort HTTP 202 mit einer
batch_idundurl_countzurück. - Jede URL wird im Hintergrund konvertiert, in den Storage hochgeladen und einzeln nachverfolgt.
- Überwache den Abschluss über Batch-Status-Polling, E-Mail-Benachrichtigung oder Webhook-Callback.
E-Mail-Benachrichtigung#
Standardmäßig wird eine Abschluss-E-Mail an die E-Mail-Adresse des Projektinhabers gesendet. Überschreibe dies mit notification_email:
{
"url": ["https://example.com/page1", "https://example.com/page2"],
"async_mode": true,
"notification_email": "[email protected]"
}
Webhook-Callback#
Gib eine callback_url an, um bei Abschluss automatisch eine POST-Benachrichtigung zu erhalten:
{
"url": ["https://example.com/page1", "https://example.com/page2"],
"async_mode": true,
"callback_url": "https://your-server.com/webhook/enconvert"
}
Der Webhook wird mit einem 30-Sekunden-Timeout gesendet und betrachtet HTTP 200, 201, 202 und 204 als erfolgreiche Zustellung.
Batch- und Massenverarbeitung#
Konvertiere mehrere URLs in einer einzigen Anfrage. Erfordert den Async-Modus und einen privaten Schlüssel.
Einzelne Ausgabe (Standard)#
Jede URL erzeugt eine separate Markdown-Datei:
{
"url": [
"https://example.com/post-1",
"https://example.com/post-2",
"https://example.com/post-3"
],
"async_mode": true
}
ZIP-Bundle-Ausgabe#
Bündle alle Markdown-Dateien in ein einzelnes ZIP-Archiv:
{
"url": [
"https://example.com/post-1",
"https://example.com/post-2",
"https://example.com/post-3"
],
"async_mode": true,
"output_format": true,
"output_filename": "blog-archive"
}
Die ZIP-Datei heißt {output_filename}_{timestamp}.zip oder batch_{timestamp}.zip, wenn kein benutzerdefinierter Name angegeben wird.
Codebeispiele#
Python (privater Schlüssel)#
import requests
response = requests.post(
"https://api.enconvert.com/v1/convert/url-to-markdown",
headers={"X-API-Key": "sk_your_private_key"},
json={
"url": "https://example.com/articles/my-post",
"direct_download": True
}
)
response.raise_for_status()
markdown_text = response.content.decode("utf-8")
print(markdown_text)
PHP (privater Schlüssel)#
$ch = curl_init("https://api.enconvert.com/v1/convert/url-to-markdown");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: sk_your_private_key"
],
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://example.com/articles/my-post"
])
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo $data["presigned_url"];
Node.js (privater Schlüssel)#
const response = await fetch("https://api.enconvert.com/v1/convert/url-to-markdown", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_your_private_key"
},
body: JSON.stringify({
url: "https://example.com/articles/my-post"
})
});
const data = await response.json();
console.log(data.presigned_url);
Go (privater Schlüssel)#
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
body, _ := json.Marshal(map[string]interface{}{
"url": "https://example.com/articles/my-post",
})
req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/url-to-markdown", bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-API-Key", "sk_your_private_key")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
fmt.Println(string(respBody))
}
JavaScript -- Browser (öffentlicher Schlüssel)#
// Step 1: Get a JWT token
const tokenRes = await fetch("https://api.enconvert.com/v1/auth/token", {
method: "POST",
headers: { "X-API-Key": "pk_your_public_key" }
});
const { token } = await tokenRes.json();
// Step 2: Convert URL to Markdown (public keys receive raw bytes)
const convertRes = await fetch("https://api.enconvert.com/v1/convert/url-to-markdown", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify({
url: "https://example.com/articles/my-post"
})
});
const markdown = await convertRes.text();
console.log(markdown);
React (öffentlicher Schlüssel)#
import { useState } from "react";
function UrlToMarkdown() {
const [loading, setLoading] = useState(false);
const [markdown, setMarkdown] = useState("");
async function convertUrl() {
setLoading(true);
try {
// Get JWT token
const tokenRes = await fetch("https://api.enconvert.com/v1/auth/token", {
method: "POST",
headers: { "X-API-Key": "pk_your_public_key" }
});
const { token } = await tokenRes.json();
// Convert
const convertRes = await fetch("https://api.enconvert.com/v1/convert/url-to-markdown", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify({ url: "https://example.com/articles/my-post" })
});
setMarkdown(await convertRes.text());
} finally {
setLoading(false);
}
}
return (
<div>
<button onClick={convertUrl} disabled={loading}>
{loading ? "Converting..." : "Convert to Markdown"}
</button>
{markdown && <pre>{markdown}</pre>}
</div>
);
}
export default UrlToMarkdown;
Fehlerantworten#
| Status | Condition |
|---|---|
400 Bad Request |
Fehlender oder leerer url-Parameter |
400 Bad Request |
output_format=true mit einer einzelnen URL (erfordert mehrere URLs) |
400 Bad Request |
direct_download=true mit mehreren URLs |
400 Bad Request |
direct_download=true mit async_mode=true |
400 Bad Request |
Ungültiges auth-Objekt (fehlendes username oder password) |
400 Bad Request |
Ungültige cookies (kein Array, mehr als 50 Einträge, fehlende Pflichtfelder) |
400 Bad Request |
Ungültige headers (kein Objekt, mehr als 20 Einträge, blockierte Header-Namen, nicht-String-Werte) |
400 Bad Request |
Widersprüchliche auth- und benutzerdefinierter Authorization-Header |
400 Bad Request |
Öffentlicher Schlüssel versucht mehrere URLs zu verwenden |
401 Unauthorized |
Fehlender oder ungültiger API-Key / JWT-Token |
402 Payment Required |
Monatliches Ops-Kontingent aufgebraucht |
402 Payment Required |
Batch würde das verbleibende monatliche Ops-Kontingent überschreiten |
402 Payment Required |
Speicherlimit erreicht |
403 Forbidden |
Endpunkt nicht in den erlaubten Endpunkten des API-Keys |
403 Forbidden |
Funktion im aktuellen Plan nicht verfügbar (Async, Webhook, ZIP, Basic Auth) |
403 Forbidden |
Batch-Größe überschreitet das Batch-Limit des Plans |
404 Not Found |
Job-ID nicht gefunden (beim Abfragen des Status) |
500 Internal Server Error |
Konvertierung fehlgeschlagen (Browser-Absturz, Navigationsfehler, Extraktionsfehler) |
Limits#
| Limit | Value |
|---|---|
| Timeout für Seitennavigation | 60 Sekunden |
| Ladezeit-Timeout pro Bild | 5 Sekunden |
| Timeout für Cookie-Banner-Schließen | 3 Sekunden |
| Maximale Cookies pro Anfrage | 50 |
| Maximale benutzerdefinierte Header pro Anfrage | 20 |
| Monatliche Operationen | Planabhängig (Founding: 500) |
| Batch-Größe | Planabhängig (Founding: deaktiviert) |
| Dateiaufbewahrung | Planabhängig (Founding: 1 Stunde) |
| Timeout für Webhook-Zustellung | 30 Sekunden |
Häufig gestellte Fragen#
Wie konvertiere ich eine Webseite mit einer REST-API in Markdown?#
Sende eine POST-Anfrage an /v1/convert/url-to-markdown mit einer url im JSON-Body und deinem Key im X-API-Key-Header. Du erhältst eine JSON-Antwort mit einer presigned_url zur Markdown-Datei zurück, oder die rohen UTF-8-Markdown-Bytes, wenn du direct_download=true setzt.
Kann ich Webseiten für LLM- und RAG-Pipelines in Markdown konvertieren?#
Ja. Der Output ist für LLM-Ingestion gebaut. Der Readability-Algorithmus (dieselbe Bibliothek hinter der Firefox Reader View) isoliert den Hauptartikel, Boilerplate wie <nav>, <footer>, Scripts und Formulare wird entfernt, jeder relative Link und jede relative Bild-URL wird zu einer absoluten URL aufgelöst, und ein YAML-Frontmatter-Block enthält die Seiten-url, title, description, links und images.
Kann ich mehrere URLs in einer API-Anfrage in Markdown konvertieren?#
Ja. Übergib ein Array von URLs in url mit async_mode=true (erfordert einen privaten Schlüssel und einen Plan mit Batch-Zugriff); die API gibt HTTP 202 mit einer batch_id zurück, die du über GET /v1/convert/batch/{batch_id} abfragst. Setze output_format=true, um alle Markdown-Dateien in ein einzelnes ZIP-Archiv zu bündeln.
Warum haben manche Bilder in meinem Markdown-Output Platzhalter-Werte für src?#
Das passiert, wenn load_media=false ist. Die Extraktion ist dann schneller, aber lazy-geladene Bilder können Platzhalter-Werte bei src behalten. Lass load_media und enable_scroll auf ihrem Standardwert true, damit die Seite gescrollt wird, um Lazy-Loader auszulösen, und jedes Bild vor der Erfassung fertig lädt (5-Sekunden-Timeout pro Bild).
Funktioniert die URL zu Markdown API auf Seiten hinter einem Login?#
Ja, bei Plänen mit Basic-Auth-Zugriff: Übergib auth mit username und password für HTTP Basic Auth, injiziere bis zu 50 Session-cookies, oder sende bis zu 20 benutzerdefinierte headers. Das ist nützlich für Mitglieder-exklusive oder Staging-Artikelseiten.