Strukturierte Daten von Websites extrahieren (API)#

Private Beta. Distill ist heute mit deinem normalen API-Schlüssel aufrufbar, in jedem Tarif einschließlich Founding, und zieht wie jeder andere Aufruf von deinem monatlichen Ops-Kontingent ab. Angekündigt oder allgemein verfügbar ist Distill nicht: Request- und Response-Formen können sich jederzeit ohne Vorankündigung ändern, und es gibt keine Stabilitäts- oder Supportzusage, baue also noch nichts Tragendes darauf. Die Roadmap steht unter Demnächst, und jedes Release wird im Changelog angekündigt.

POST /v2/distill ist eine API, um strukturierte Daten aus Websites zu extrahieren: Sie zieht Felder aus einer oder mehreren URLs heraus, passend zu einem von dir gelieferten Schema, entweder einem JSON-Schema-Objekt oder einer flachen {field: description}-Map. Sie läuft als Zwei-Pass-Engine: zuerst ein kostenloser CSS-Pass (Crawl4AIs JsonCssExtractionStrategy, gesteuert von deinen Selektoren), dann ein gedeckelter, LLM-gestützter Pass für die Felder, die der CSS-Pass leer gelassen hat. Das data-Feld der Antwort kommt garantiert exakt in der angeforderten Form zurück. Es wird EnConverts Antwort auf Firecrawl /extract sein.

Hier der kleinste nützliche Aufruf. Sende eine URL und ein flaches {field: description}-Schema und erhalte die extrahierten Felder zurück:

curl -X POST https://api.enconvert.com/v2/distill \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com/product/widget"],
    "schema": {
      "name": "the product name",
      "price": "the listed price",
      "in_stock": "whether it is in stock"
    }
  }'

Die Antwort enthält ein Ergebnis pro URL, die extrahierten data und welche Stufe sie geliefert hat:

{
    "operation_id": "dst_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
    "total": 1,
    "completed": 1,
    "failed": 0,
    "results": [
        {
            "url": "https://example.com/product/widget",
            "url_final": "https://example.com/product/widget",
            "status": "completed",
            "data": {
                "name": "Widget Pro",
                "price": "$49.00",
                "in_stock": "yes"
            },
            "extraction_tier": "llm",
            "fields_from_css": 0,
            "fields_from_llm": 3,
            "render_quality": 0.91,
            "tokens": {"input": 4120, "output": 38},
            "cost_cents": 0.45,
            "warnings": []
        }
    ],
    "total_cost_cents": 0.45,
    "warnings": []
}

Endpunkte#

Methode Pfad Zweck
POST /v2/distill Führt distill für eine explizite URL-Liste aus, oder ermittelt zunächst mit discover die URLs einer Site und führt distill für jede aus, jeweils gegen ein Schema.

Content-Type: application/json.

Anders als perceive ist distill ein einzelner synchroner Endpunkt: Es gibt keinen separaten GET-Re-Fetch oder asynchronen Batch-Pfad. Jede URL wird sequenziell über das gemeinsam genutzte Headless-Chrome-Singleton gerendert, und die vollständige Ergebnismenge kommt in einer einzigen Antwort zurück.


Authentifizierung#

Authentifiziere dich mit einem privaten Schlüssel im X-API-Key-Header für Server-zu-Server-Aufrufe. Diesen Weg verwenden die folgenden Beispiele.

X-API-Key: sk_your_private_key

Öffentliche Schlüssel mit einem JWT-Bearer-Token funktionieren ebenfalls, nach demselben Ablauf wie bei jedem anderen Endpunkt: Erzeuge ein Token mit deinem pk_-Schlüssel und sende es als Authorization: Bearer <token>. Der vollständige Ablauf, einschließlich Domain-Lock und Token-Refresh, steht in der Authentifizierungsanleitung.

Jeder API-Schlüssel trägt eine Allowlist erlaubter Endpunkte. Steht /v2/distill nicht auf der Liste des Schlüssels, wird die Anfrage mit 403 abgelehnt.


Wie distill funktioniert#

Eine Anfrage führt distill für eine Liste von URLs gegen ein Schema aus. Der Ablauf ist für jede URL derselbe:

  1. URL-Liste auflösen. Bei urls ist die Liste exakt das, was du gesendet hast (dedupliziert, Reihenfolge erhalten). Bei discover_from führt distill zuerst discover auf der Seed-URL aus (parst die Sitemap, crawlt, oder beides) und verarbeitet anschließend die entdeckten URLs bis zu max_pages.
  2. Rendern. Jede URL wird einmal in Headless-Chrome gerendert, über dieselbe Capture-Pipeline, die auch perceive antreibt. Das Rendering wird auf SSRF geprüft und, falls respect_robots=true, gegen die robots.txt der Site abgeglichen. Es werden keine Artefakte in den Storage hochgeladen, denn distill braucht nur das gerenderte DOM.
  3. Pass 1: CSS (kostenlos). Hast du ein css_schema mitgeschickt, läuft der CSS-Extraktor über das gerenderte HTML und füllt jedes selektor-adressierbare Feld zu null LLM-Kosten. Dieser Pass ist auf 10 Sekunden zeitlich begrenzt; bei Timeout fällt die URL mit einer Warnung in den LLM-Pass durch.
  4. Pass 2: LLM (gedeckelt, nur bei Bedarf). Distill sammelt die Schema-Felder, die der CSS-Pass fehlend oder leer gelassen hat, und eskaliert nur diese Felder an die LLM-Stufe, unter harten Budgetgrenzen pro Aufruf und pro Zeitraum. Hat dein Plan keine LLM-Stufe, wurde die Seite als blockiert markiert, oder wird eine Budgetgrenze erreicht, wird der LLM-Pass übersprungen, und die fehlenden Felder kommen mit einer Warnung als null zurück.
  5. Normalisieren. Das zusammengeführte Ergebnis wird exakt auf die Keys deines Schemas umgeformt: Fehlende Skalare werden zu null, fehlende Arrays zu [], und alle zusätzlichen Keys werden verworfen. Die Formgarantie gilt unabhängig davon, was CSS oder das LLM geliefert haben.

Pro abgeschlossener URL wird eine Op berechnet, und erst nachdem die URL fertig ist. Render-Fehlschläge (SSRF-Ablehnung, Robots-Blockade, ein abgestürztes Rendering) erzeugen eine Ergebniszeile mit failed und kosten keine Ops.


Request-Parameter#

Du musst genau eines von urls oder discover_from angeben, plus ein schema. Beides oder keines von beiden zu senden, ergibt 422.

Quelle: explizite URLs#

Parameter Typ Standard Beschreibung
urls string[] -- Explizite URLs für distill. Jede muss mit http:// oder https:// beginnen und darf höchstens 2,048 Zeichen lang sein. Max. 50 URLs pro Request (MAX_DISTILL_URLS). Schließt sich mit discover_from gegenseitig aus.

Quelle: discover, dann distill#

Parameter Typ Standard Beschreibung
discover_from object -- Ermittelt zunächst mit discover die URLs einer Site, führt distill dann für jede einzelne aus. Schließt sich mit urls gegenseitig aus. Erfordert das Plan-Flag discover_enabled (sonst 402).
discover_from.url string -- Seed-URL. Muss mit http:// oder https:// beginnen. Max. 2,048 Zeichen.
discover_from.mode string hybrid sitemap, crawl oder hybrid. Dieselben Modi wie beim discover-Endpunkt.
discover_from.max_pages integer 10 Obergrenze für die Anzahl der über discover ermittelten und mit distill verarbeiteten URLs, von 1 bis 50. Jede ist ein vollständiges Rendering, daher begrenzt durch MAX_DISTILL_URLS.

Schema oder Prompt#

Gib entweder ein schema (die gewünschte Ausgabeform) oder einen prompt (eine Beschreibung in natürlicher Sprache, was extrahiert werden soll) an. Genau eines von beiden ist erforderlich; sendest du beide, gewinnt schema.

Parameter Typ Standard Beschreibung
schema object null Die Ausgabeform, gesendet unter dem JSON-Key schema. Entweder ein JSON-Schema-Objekt ({"type": "object", "properties": {...}}) oder eine nachsichtige flache {field: description}-Map. Max. 200 Top-Level-Properties. Die data der Antwort entspricht garantiert dieser Form. Ein strukturell ungültiges Schema ergibt 422.
prompt string null Eine Beschreibung in natürlicher Sprache, was extrahiert werden soll. Wird er ohne schema angegeben, synthetisiert distill daraus das Extraktionsschema (ein einzelnes Modell) und führt dann die normale Zwei-Pass-Engine aus. Max. 2,000 Zeichen.

Das Schema ist der Vertrag. Sendest du ein JSON-Schema-Objekt, liest distill dessen properties; sendest du eine flache Map, benennt jeder Key ein Feld, und jeder Value ist die Beschreibung, die ans LLM übergeben wird. So oder so kommt data mit exakt den Top-Level-Keys des Schemas zurück.

Prompt-only-Modus. Sendest du einen prompt statt eines schema, synthetisiert distill zuerst ein Schema von Feldern aus deinem Prompt und extrahiert dann dagegen. Die synthetisierten Felder werden in der Antwort als synthesized_schema zurückgegeben. Der Prompt-only-Modus verwendet die LLM-Extraktionsstufe und erfordert einen Plan, der sie enthält; ohne einen solchen liefert distill eine klare Warnung, statt zu raten.

CSS-Schema (optional)#

Liefere ein css_schema, um Felder kostenlos zu beantworten, bevor ein LLM-Aufruf stattfindet. Ohne es fällt jedes Feld direkt in den LLM-Pass.

Parameter Typ Standard Beschreibung
css_schema.baseSelector string -- CSS-Selektor für den sich wiederholenden Container; pro Treffer wird ein Datensatz extrahiert. 1 bis 1,024 Zeichen. Erforderlich, wenn css_schema vorhanden ist.
css_schema.fields CssField[] -- 1 bis 128 Felddefinitionen, die aus jedem Container ausgelesen werden. Erforderlich.
css_schema.name string "distill" Optionale Bezeichnung für das Schema. Max. 128 Zeichen.
css_schema.target_field string abgeleitet Welche Top-Level-Ausgabe-Property die CSS-Datensätze füllen: Eine Array-Property erhält die vollständige Datensatzliste, eine Skalar-/Objekt-Property erhält den ersten Datensatz. Fehlt der Wert, ermittelt distill die Property automatisch, sofern das Schema genau eine Array-Property hat. Max. 128 Zeichen.

Jeder Eintrag in fields ist ein CssField:

Feld Typ Standard Beschreibung
name string -- Ausgabe-Key für dieses Feld. 1 bis 128 Zeichen. Erforderlich.
type string -- Eine von text, attribute, html, regex, nested, list, nested_list. Erforderlich.
selector string null CSS-Sub-Selektor. Optional bei Blatt-Typen (text/attribute/html/regex); erforderlich bei nested/list/nested_list. Max. 1,024 Zeichen.
attribute string null Name des auszulesenden Attributs. Erforderlich, wenn type gleich attribute ist. Max. 128 Zeichen.
pattern string null Regex-Pattern. Erforderlich, wenn type gleich regex ist. Wird am Edge kompiliert; ein Pattern mit verschachtelten, erneut quantifizierten Gruppen (eine ReDoS-Form wie (a+)+) wird mit 422 abgelehnt. Max. 1,024 Zeichen.
default any null Wert, wenn der Selektor nichts trifft.
transform string null Eine von lowercase, uppercase, strip.
fields CssField[] null Kindfelder, für nested/list/nested_list. Max. 64 Kinder; maximale Verschachtelungstiefe 5.

Wichtig zu wissen: Der Feldtyp computed aus Crawl4AI wird bewusst nicht akzeptiert. Seine Expression-Form führt eval auf Caller-Input aus, und seine Callable-Form kann keine JSON-Grenze überqueren, weshalb distill nur die sieben oben genannten sicheren Typen zulässt.

Render-Einstellungen#

Distill rendert nur das DOM und stellt daher nur eine kleine Teilmenge der perceive-Render-Optionen bereit.

Parameter Typ Standard Beschreibung
wait_for string null Wartet nach der Navigation auf einen CSS-Selektor oder einen JS-Ausdruck ("js:window.dataReady === true"). Max. 1,024 Zeichen.
wait_timeout_ms integer 30000 Wie lange wait_for warten darf, in Millisekunden. 0 bis 60,000.
headers object null Benutzerdefinierte Request-Header für das Rendering.
cookies array null Cookies, die vor der Navigation injiziert werden.
respect_robots boolean false Bei true wird eine von der robots.txt der Site untersagte URL abgelehnt, und das Ergebnis dieser URL wird als failed markiert.

Antwort#

POST /v2/distill liefert eine DistillResponse:

Feld Typ Beschreibung
operation_id string Opake ID (dst_...). Bei Support-Anfragen angeben.
total integer Anzahl der verarbeiteten URLs (Zeilen in results).
completed integer URLs, die gerendert wurden und ein data-Objekt geliefert haben.
failed integer URLs, deren Rendering abgelehnt wurde oder abgestürzt ist.
results object[] Ein DistillItemResult pro URL, unten beschrieben.
total_cost_cents number Summe der LLM-Kosten pro URL über die gesamte Anfrage, in Cent.
synthesized_schema object Nur im Prompt-only-Modus vorhanden: das Schema, das aus deinem prompt synthetisiert und für die Extraktion verwendet wurde.
warnings string[] Hinweise auf Request-Ebene (z. B. Ops-Kontingent mitten in der Liste erschöpft, Crawl-Fehler bei discover).

Jeder Eintrag in results ist ein DistillItemResult:

Feld Typ Beschreibung
url string Die URL, die du gesendet hast (oder die ermittelt wurde).
url_final string Die URL nach Redirects. Entfällt bei einer failed-Zeile.
status string completed oder failed.
data object Die extrahierten Daten, normalisiert auf exakt die Keys deines Schemas. null bei einer failed-Zeile.
extraction_tier string css (nur CSS), llm (nur LLM), mixed (beide haben beigetragen) oder none (nichts gefunden).
fields_from_css integer Anzahl der Felder, die der CSS-Pass gefüllt hat.
fields_from_llm integer Anzahl der Felder, die der LLM-Pass gefüllt hat.
render_quality number 0.0 bis 1.0. Niedrige Werte weisen auf Anti-Bot-Challenges oder Login-Walls hin.
tokens object {input, output} verwendete LLM-Tokens. Null, außer der LLM-Pass lief.
cost_cents number LLM-Kosten in Cent für diese URL. Null, außer der LLM-Pass lief.
error string Nur gesetzt, wenn status gleich failed ist. Eine generische Meldung, denn interne Render-Details bleiben serverseitig.
warnings string[] Hinweise pro URL: ein CSS-Timeout, ein übersprungener LLM-Pass, eine erreichte Budgetgrenze.

Um ganz klar zu sein: Die Antwort enthält keine signierten Download-URLs und keine gespeicherten Artefakte. Distill liefert die strukturierten data inline und sonst nichts. Willst du zusätzlich das Markdown, HTML, einen Screenshot oder ein PDF der Seite, ist dafür perceive da.


Das Zwei-Pass-Kostenmodell#

Der CSS-Pass ist kostenlos. Der LLM-Pass kostet Geld, daher löst distill ihn so gezielt wie möglich aus und deckelt ihn aus mehreren Richtungen.

Es eskaliert nur die fehlenden Felder. Nach dem CSS-Pass berechnet distill, welche Schema-Felder noch leer sind: ein Skalar, der als null/"" zurückkam, ein Array, das leer zurückkam, oder ein Array, dessen Elemente ein deklariertes Unterfeld vermissen lassen. Nur diese Feldnamen fließen in ein reduziertes Schema für den LLM-Aufruf ein, was Prompt und Kosten minimal hält.

Der LLM-Pass wird vollständig übersprungen, wenn eine der folgenden Bedingungen zutrifft; distill liefert dann das reine CSS-Ergebnis mit einer Warnung, statt zu überziehen:

  • Dein Plan hat keine LLM-Stufe (llm_extraction_enabled plus einen agent_model_tier ungleich none).
  • Die render_quality der Seite hat sie als durch Anti-Bot-Schutz blockiert markiert.
  • Das Pro-Request-LLM-Budget für diesen Aufruf ist erreicht, oder die Pro-Zeitraum-Budgetgrenze ist erreicht.

Die Budgetgrenzen sind gestaffelt:

Grenze Wert Geltungsbereich
Pro Aufruf $0.05 (PER_REQUEST_CAP_CENTS) Worst-Case-Kostenprognose eines einzelnen LLM-Aufrufs. Darüber → wird übersprungen, noch bevor Netzwerk-I/O stattfindet.
Pro Request $0.50 (_REQUEST_LLM_BUDGET_CENTS) Gesamte LLM-Ausgaben über alle URLs eines /v2/distill-Aufrufs. Verbleibende URLs liefern nur CSS-Ergebnisse.
Eskalationen pro Request 50 (_MAX_LLM_ESCALATIONS) Höchstens ein LLM-Aufruf pro URL, hart gedeckelt.
Pro Zeitraum Dein monatliches AI-Credit-Guthaben: $5 / $15 / $40 pro Monat auf Indie / Studio / Production, ungenutzte Credits werden übertragen ch_usage_periods.llm_cost_cents gegen die gewährten Credits der Periode (usage.reserve_llm_budget).

Hinweis. Das Pro-Zeitraum-Budget wird vor dem Aufruf atomar reserviert und danach auf die tatsächlichen Kosten abgerechnet, sodass gleichzeitige Aufrufe die Grenze nicht gemeinsam überschreiten können. Ein Projekt ohne aktive Usage-Period-Zeile schlägt sicherheitshalber fehl (fail closed), denn Ausgaben, die EnConvert nicht zuordnen kann, sind Ausgaben, die nicht getätigt werden. Wird eine Grenze erreicht, kommen die betroffenen Felder mit einer Warnung als null zurück; die Anfrage ist trotzdem erfolgreich.

Läuft der LLM-Pass, meldet extraction_tier llm oder mixed, und tokens sowie cost_cents melden die entstandenen Kosten. Läuft er nicht, sind beide null.


CSS-Datensätze auf dein Schema abbilden#

Der Standardfall ist eine Listing-Seite: eine sich wiederholende Zeile und ein Ausgabeschema mit einer Array-Property, die die Zeilen aufnimmt. Gib distill ein css_schema, dessen baseSelector die Zeile trifft und dessen fields die Spalten auslesen, und es füllt das Array kostenlos:

curl -X POST https://api.enconvert.com/v2/distill \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com/products"],
    "schema": {
      "type": "object",
      "properties": {
        "products": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": {"type": "string"},
              "price": {"type": "string"},
              "sku": {"type": "string"}
            }
          }
        }
      }
    },
    "css_schema": {
      "baseSelector": ".product-card",
      "target_field": "products",
      "fields": [
        {"name": "name", "type": "text", "selector": ".title"},
        {"name": "price", "type": "text", "selector": ".price"},
        {"name": "sku", "type": "attribute",
         "selector": ".product-card", "attribute": "data-sku"}
      ]
    }
  }'

Wie Datensätze im Schema landen:

  • target_field auf eine Array-Property gesetzt → diese Property erhält die vollständige Datensatzliste.
  • target_field auf eine Skalar-/Objekt-Property gesetzt → sie erhält den ersten Datensatz.
  • target_field weggelassen, Schema hat genau eine Array-Property → distill ermittelt sie automatisch und füllt diese Property.
  • Andernfalls → der erste Datensatz wird als einzelnes flaches Objekt behandelt, und seine passenden Keys werden auf die oberste Ebene gehoben.

Füllt CSS das Array, aber einigen Elementen fehlt ein deklariertes Unterfeld (sagen wir, sku fehlt bei der Hälfte der Karten), eskaliert distill products an den LLM-Pass, um die Lücken zu füllen. Das ist der Zwei-Pass-Unterschied gegenüber einem simplen Scraper: strukturiert, wo es geht, modellgestützt, wo es sein muss.


Codebeispiele#

curl: flaches Schema, nur LLM#

curl -X POST https://api.enconvert.com/v2/distill \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com/article"],
    "schema": {
      "headline": "the article headline",
      "author": "the author name",
      "published": "the publish date"
    }
  }'

curl: discover, dann distill#

curl -X POST https://api.enconvert.com/v2/distill \
  -H "X-API-Key: sk_your_private_key" \
  -H "Content-Type: application/json" \
  -d '{
    "discover_from": {
      "url": "https://example.com/blog",
      "mode": "sitemap",
      "max_pages": 25
    },
    "schema": {
      "title": "the post title",
      "summary": "a one-line summary"
    }
  }'

Python#

import requests

response = requests.post(
    "https://api.enconvert.com/v2/distill",
    headers={"X-API-Key": "sk_your_private_key"},
    json={
        "urls": ["https://example.com/product/widget"],
        "schema": {
            "name": "the product name",
            "price": "the listed price",
            "in_stock": "whether it is in stock",
        },
    },
)
response.raise_for_status()
result = response.json()

for item in result["results"]:
    if item["status"] == "completed":
        print(item["url"], "->", item["data"])
    else:
        print(item["url"], "FAILED:", item["error"])

print("total cost (cents):", result["total_cost_cents"])

Node.js#

const res = await fetch("https://api.enconvert.com/v2/distill", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "X-API-Key": "sk_your_private_key"
    },
    body: JSON.stringify({
        urls: ["https://example.com/product/widget"],
        schema: {
            name: "the product name",
            price: "the listed price",
            in_stock: "whether it is in stock"
        }
    })
});

const result = await res.json();

for (const item of result.results) {
    if (item.status === "completed") {
        console.log(item.url, "->", item.data);
    } else {
        console.log(item.url, "FAILED:", item.error);
    }
}

console.log("total cost (cents):", result.total_cost_cents);

Fehlerantworten#

Status Bedingung
400 Bad Request Eine URL (oder der discover_from-Seed) löst zu einer privaten, Loopback- oder Link-Local-Adresse auf, hat keinen Hostnamen oder scheitert anderweitig an der SSRF-Prüfung. Wird pro URL während des Renderings ausgelöst.
401 Unauthorized Fehlender oder ungültiger API-Schlüssel / JWT-Token.
402 Payment Required distill ist nicht in deinem aktuellen Plan enthalten, dein monatliches Ops-Kontingent ist erschöpft, oder discover_from wurde ohne das Plan-Flag discover_enabled gesendet.
403 Forbidden /v2/distill steht nicht in den erlaubten Endpunkten des API-Schlüssels.
422 Unprocessable Entity Kein schema, beides oder keines von urls/discover_from, ein strukturell ungültiges Schema, über 200 Schema-Properties, ein ungültiges CssField (fehlendes attribute/pattern/fields für seinen Typ, ein nicht kompilierbarer oder ReDoS-anfälliger Regex), oder CSS-Feld-Verschachtelung tiefer als 5.
500 Internal Server Error Die Orchestrierung ist unerwartet fehlgeschlagen. Die Meldung enthält die operation_id zur Angabe beim Support.

Ein paar Status-Feinheiten, die man auseinanderhalten sollte: Eine einzelne URL, deren Rendering wegen SSRF abgelehnt wird, führt nur dann zu einem 400, wenn sie der Seed einer discover_from-Anfrage ist; bei einer expliziten urls-Liste wird eine per-URL-Render-Ablehnung stattdessen zu einer Ergebniszeile mit failed, statt die gesamte Anfrage scheitern zu lassen. Eine erreichte LLM-Budgetgrenze ist niemals ein Fehler, denn sie degradiert zu einem reinen CSS-Ergebnis mit einer Warnung. Die vollständige Status-Code-Referenz steht in der Fehlercode-Anleitung.


Limits#

Limit Wert
URLs pro Request (urls) 50 (MAX_DISTILL_URLS)
discover_from.max_pages 1 bis 50
URL-Länge 2,048 Zeichen
Schema-Top-Level-Properties 200 (MAX_SCHEMA_PROPERTIES)
css_schema.fields 1 bis 128
CssField.fields-Kinder 64
CSS-Feld-Verschachtelungstiefe 5 (MAX_CSS_FIELD_DEPTH)
wait_for-Länge 1,024 Zeichen
wait_timeout_ms 0 bis 60,000 ms
CSS-Pass-Timeout 10 Sekunden pro URL
LLM-Grenze pro Aufruf $0.05
LLM-Grenze pro Request $0.50
LLM-Eskalationen pro Request 50
LLM-Grenze pro Zeitraum Monatliches AI-Credit-Guthaben ($5 / $15 / $40 je Tarif; ungenutzte Credits werden übertragen)
Monatliche Ops (über alle Endpunkte geteilt, 1 pro abgeschlossener URL) 500 / 3.000 / 15.000 / 50.000 je Tarif; siehe Preise

Häufig gestellte Fragen#

Wie extrahiere ich strukturierte Daten von einer Website mit einer REST-API?#

Sende POST /v2/distill mit urls (bis zu 50 pro Request) und einem schema, entweder ein JSON-Schema-Objekt oder eine flache {field: description}-Map. Die data der Antwort kommt normalisiert auf exakt die Top-Level-Keys deines Schemas zurück.

Kann ich eine Website ohne CSS-Selektoren in ein JSON-Schema scrapen?#

Ja. css_schema ist optional, und ohne es fällt jedes Feld direkt in den LLM-gestützten Pass. Ein mitgeschicktes css_schema füllt selektor-adressierbare Felder kostenlos und eskaliert nur die Felder, die der CSS-Pass leer gelassen hat.

Was kostet der LLM-Extraktionspass, und wie wird er gedeckelt?#

Die Budgetgrenzen sind gestaffelt: $0.05 pro LLM-Aufruf, $0.50 pro /v2/distill-Request, höchstens 50 Eskalationen pro Request und pro Zeitraum dein monatliches AI-Credit-Guthaben ($5 / $15 / $40 auf Indie / Studio / Production; ungenutzte Credits werden übertragen). LLM-Extraktion verbraucht Credits, keine Ops. Das Erreichen einer Grenze lässt die Anfrage nie scheitern: Betroffene Felder kommen mit einer Warnung als null zurück.

Warum sind manche Felder in meiner distill-Antwort null?#

Fehlende Skalare werden auf null normalisiert (fehlende Arrays auf []), um die Formgarantie zu wahren. Der LLM-Pass wird übersprungen (mit einer Warnung), wenn dein Plan keine LLM-Stufe hat, die render_quality der Seite sie als blockiert markiert hat oder eine Budgetgrenze erreicht wurde.

Kann ich eine ganze Site crawlen und aus jeder Seite dasselbe Schema extrahieren?#

Ja. Sende statt urls ein discover_from mit einer Seed-url, einem mode (sitemap, crawl oder hybrid) und max_pages (1 bis 50). Das erfordert das Plan-Flag discover_enabled; ohne es wird die Anfrage mit 402 abgelehnt.