Java SDK für Dateikonvertierung#
com.enconvert:enconvert-sdk ist der offizielle Java-Client für die EnConvert API. Eine einzige Maven- oder Gradle-Abhängigkeit liefert dir die Datei-Konvertierung (URL zu PDF, DOCX zu PDF, HEIC zu WebP, alles zu Markdown) plus die V2-Oberfläche für Web-Intelligence: perceive, discover, lookup, distill, ingest und watch. Das SDK zielt auf Java 17 und neuer, läuft auf dem im JDK enthaltenen java.net.http.HttpClient und zieht Gson als einzige Drittanbieter-Abhängigkeit nach. Jeder Aufruf ist eine schlichte blockierende Methode, die ein typisiertes Record zurückgibt, und lange Konvertierungen erholen sich transparent von Reverse-Proxy-Timeouts, indem sie den Job-Status abfragen.
com.enconvert:enconvert-sdk:0.0.1 · Quelle: conversionapi/java-sdk · Java: 17+ · Abhängigkeiten: nur Gson
Installation#
// build.gradle
dependencies {
implementation 'com.enconvert:enconvert-sdk:0.0.1'
}
// build.gradle.kts
dependencies {
implementation("com.enconvert:enconvert-sdk:0.0.1")
}
<!-- pom.xml -->
<dependency>
<groupId>com.enconvert</groupId>
<artifactId>enconvert-sdk</artifactId>
<version>0.0.1</version>
</dependency>
HTTP wird vom java.net.http.HttpClient aus dem JDK erledigt. Das einzige Drittanbieter-Artefakt, das mitkommt, ist Gson für JSON, deklariert als api-Abhängigkeit und damit auf deinem Compile-Classpath sichtbar.
Schnellstart#
import com.enconvert.Enconvert;
import com.enconvert.model.ConversionResult;
import com.enconvert.model.UrlToPdfOptions;
import com.enconvert.model.v2.PerceiveOptions;
import com.enconvert.model.v2.PerceiveResult;
import java.util.List;
Enconvert client = new Enconvert(System.getenv("ENCONVERT_API_KEY"));
ConversionResult pdf = client.convertUrlToPdf("https://example.com",
UrlToPdfOptions.builder().saveTo("page.pdf").build());
System.out.println(pdf.presignedUrl());
// Lies eine Seite so, wie es dein Agent tun sollte, mit angehängtem Quality-Score.
PerceiveResult page = client.v2.perceive("https://example.com",
PerceiveOptions.builder().outputs(List.of("markdown", "structured")).build());
System.out.println(page.outputs().get("markdown").url());
System.out.println(page.renderQuality()); // z. B. 0.93
Jede Options-Klasse ist ein unveränderlicher Builder und jede Antwort ein Java-record, sodass sich Zugriffe als pdf.presignedUrl() und page.renderQuality() lesen. Der Client hält einen gemeinsamen HttpClient und keinen veränderlichen Zustand pro Anfrage, eine einzelne Instanz kann also ein Singleton oder eine über Threads geteilte Spring-Bean sein. Die Snippets unten lassen Imports weg: Options- und Antworttypen liegen in com.enconvert.model (Konvertierung) und com.enconvert.model.v2 (Web-Intelligence), Exceptions in com.enconvert.exceptions.
Was der Client bereitstellt#
Enconvert trägt die Konvertierungs-Oberfläche direkt. Die Web-Intelligence-Oberfläche liegt auf dem öffentlichen finalen Feld client.v2, einer Instanz von EnconvertV2.
| Gruppe | Methoden | Rückgabe |
|---|---|---|
| Einzelne URL | convertUrlToPdf, convertUrlToScreenshot, convertUrlToMarkdown |
ConversionResult |
| Datei-Upload | convertImage, convertDocument, convertToMarkdown, convertToPdf |
ConversionResult |
| Ganze Website | convertWebsiteToPdf, convertWebsiteToScreenshot |
BatchSubmission |
| Status | getJobStatus, getBatchStatus, waitForBatch |
JobStatus, BatchStatus |
v2 perceive |
perceive, perceiveDirect, getPerceiveOperation, perceiveBatch, getPerceiveBatch, downloadPerceiveArtifact |
PerceiveResult, PerceiveDirectResult, PerceiveBatchResult |
v2 discover |
discover |
DiscoverResult |
v2 lookup |
lookup |
LookupResult |
v2 distill |
distill |
DistillResult |
v2 ingest |
ingest, ingestFiles, getIngestJob, listIngestJobs, cancelIngestJob, retryIngestWebhook, getWebhookSecret, rotateWebhookSecret |
IngestJob, IngestJobList, WebhookRetryResult, WebhookSecret |
v2 watch |
createWatcher, getWatcher, listWatchers, getWatcherSnapshots, updateWatcher, deleteWatcher |
Watcher, WatcherList, WatcherSnapshotList |
Die meisten Methoden haben eine kurze Überladung ohne Options-Argument, client.v2.perceive(url) und client.convertUrlToPdf(url) kompilieren also beide. convertImage, distill und ingest sind die Ausnahmen: Jede nimmt immer ihr Options-Objekt entgegen, weil Zielformat, Schema beziehungsweise Quelle erforderlich sind.
Datei-Konvertierung#
Die Konvertierungs-Endpunkte decken 43 implementierte {input}-to-{output}-Paare ab, dazu zwei automatisch erkennende Endpunkte (anything-to-markdown und anything-to-pdf) sowie die Browser-Rendering-Endpunkte. Die vollständige Parameter-Referenz steht unter Parameter und Optionen.
convertUrlToPdf#
Rendere jede öffentliche URL zu einem PDF.
ConversionResult result = client.convertUrlToPdf("https://example.com",
UrlToPdfOptions.builder()
.pdfOptions(PdfOptions.builder().pageSize("A4").orientation("landscape").build())
.singlePage(false)
.viewportWidth(1440)
.saveTo("report.pdf")
.build());
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
saveTo |
String |
keiner | Lokaler Pfad, in den das PDF geschrieben wird. Übergeordnete Verzeichnisse werden für dich angelegt. |
singlePage |
boolean |
true |
true erzeugt eine einzige fortlaufende Seite. false paginiert anhand von pdfOptions.pageSize. |
pdfOptions |
PdfOptions |
keiner | Seitengröße, Ausrichtung, Ränder, Skalierung, Graustufen, Kopf- und Fußzeile. Siehe PDF-Optionen. |
viewportWidth |
int |
1920 |
Breite des Browser-Viewports in Pixeln. |
viewportHeight |
int |
1080 |
Höhe des Browser-Viewports in Pixeln. |
loadMedia, enableScroll |
boolean |
true |
Vor der Erfassung auf Bilder und Videos warten und von oben nach unten scrollen, um Lazy-Loader auszulösen. |
outputFilename |
String |
auto | Überschreibt den generierten Dateinamen. |
auth, cookies, headers |
HttpBasicAuth, List<BrowserCookie>, Map<String, String> |
keiner | Zugangsdaten, eingeschleuste Cookies und zusätzliche Request-Header für Seiten hinter einem Login. |
convertUrlToScreenshot#
Erfasse ein PNG einer beliebigen URL. Dieselben Optionen für Viewport, Medien, Scrollen, Dateiname, Auth, Cookies und Header wie bei convertUrlToPdf, ohne singlePage und pdfOptions.
client.convertUrlToScreenshot("https://example.com",
UrlToScreenshotOptions.builder().viewportWidth(1440).saveTo("screenshot.png").build());
convertUrlToMarkdown#
Extrahiere sauberes GitHub Flavored Markdown aus einer URL. Navigation, Fußzeilen, Werbung und Skripte werden entfernt, der Haupttext des Artikels bleibt erhalten, und YAML-Frontmatter (Titel, Beschreibung, URL, Links, Bilder) wird vorangestellt. Gleicher Optionssatz wie bei convertUrlToScreenshot.
client.convertUrlToMarkdown("https://example.com/article",
UrlToMarkdownOptions.builder().saveTo("article.md").build());
convertImage#
Konvertiere zwischen jpeg, png, svg, heic und webp oder rastere ein PDF zu JPEG.
// Von einem Pfad auf der Festplatte
client.convertImage(Path.of("photo.heic"),
ConvertImageOptions.builder("webp").saveTo("photo.webp").build());
// Ein PDF rastern
client.convertImage(Path.of("scan.pdf"),
ConvertImageOptions.builder("jpeg").saveTo("scan.jpeg").build());
// Aus Bytes im Speicher mit explizitem Dateinamen
byte[] bytes = Files.readAllBytes(Path.of("photo.heic"));
client.convertImage(new FileInput(bytes, "photo.heic"),
ConvertImageOptions.builder("webp").build());
Jede Datei-Methode kennt drei Eingabe-Überladungen: java.nio.file.Path (von der Festplatte gelesen), rohe byte[] (der Dateiname ist standardmäßig upload.bin) und com.enconvert.FileInput, wenn du Bytes im Speicher mit einem echten Dateinamen kombinieren musst. Das Eingabeformat wird aus der Erweiterung aufgelöst, das Ausgabeformat ist erforderlich.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
outputFormat |
String |
Ja | Wird an ConvertImageOptions.builder(outputFormat) übergeben. Eines von jpeg, png, svg, heic, webp. Aliasse wie jpg werden normalisiert. |
saveTo |
String |
nein | Lokaler Pfad, in den das Ergebnis geschrieben wird. |
outputFilename |
String |
nein | Überschreibt den generierten Dateinamen. |
convertDocument#
Konvertiere Dokumente und strukturierte Datenformate. Das Ausgabeformat ist standardmäßig pdf.
// docx zu pdf
client.convertDocument(Path.of("report.docx"),
ConvertDocumentOptions.builder().saveTo("report.pdf").build());
// json zu yaml
client.convertDocument(Path.of("data.json"),
ConvertDocumentOptions.builder().outputFormat("yaml").saveTo("data.yaml").build());
// markdown zu pdf mit Seiteneinrichtung
client.convertDocument(Path.of("README.md"),
ConvertDocumentOptions.builder()
.outputFormat("pdf")
.pdfOptions(PdfOptions.builder()
.pageSize("A4")
.margins(new PdfMargins(20.0, 20.0, 25.0, 25.0))
.build())
.saveTo("readme.pdf")
.build());
Erkannte Eingabe-Erweiterungen: .doc, .docx, .xls, .xlsx, .ppt, .pptx, .html, .htm, .odt, .ods, .odp, .ots, .pages, .numbers, .md, .markdown, .csv, .json, .xml, .yaml, .yml, .toml.
EPUB hat kein eigenes Dokumentpaar. Schicke .epub-Dateien stattdessen durch convertToPdf oder convertToMarkdown.
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
outputFormat |
String |
"pdf" |
Zielformat. |
saveTo |
String |
keiner | Lokaler Pfad, in den das Ergebnis geschrieben wird. |
outputFilename |
String |
keiner | Überschreibt den generierten Dateinamen. |
pdfOptions |
PdfOptions |
keiner | Seiteneinrichtung, wird berücksichtigt, wenn die Ausgabe ein PDF ist. |
Unterstützte Konvertierungen#
convertImage und convertDocument prüfen das {input}-to-{output}-Paar gegen die Endpunkte, die die API tatsächlich implementiert. Ein nicht unterstütztes Paar wirft sofort eine IllegalArgumentException und listet die gültigen Ausgaben für diese Eingabe auf, statt für eine aussichtslose Anfrage einen Roundtrip zu bezahlen.
| Eingabe | Ausgaben |
|---|---|
json |
csv, toml, xml, yaml |
xml |
csv, json |
yaml |
json |
csv |
json, xml |
toml |
json |
markdown |
html, pdf |
html |
pdf |
doc, excel, ppt, odt, ods, odp, ots, pages, numbers |
pdf |
jpeg, png, svg, heic, webp |
untereinander, alle 20 Paare |
pdf |
jpeg |
Dieselbe Tabelle lässt sich zur Laufzeit über com.enconvert.Formats abfragen: Formats.validOutputsFor("json") gibt [csv, toml, xml, yaml] zurück, Formats.validOutputsFor("pdf") gibt [jpeg] zurück, und Formats.IMPLEMENTED_CONVERSIONS enthält alle 43 Endpunktnamen.
convertToMarkdown#
Schicke ein beliebiges unterstütztes Dokument durch einen automatisch erkennenden Endpunkt und erhalte sauberes Markdown zurück. Die Überschriften-Hierarchie bleibt erhalten, was diesen Schritt zu einer natürlichen ersten Stufe für eine RAG-Pipeline macht.
client.convertToMarkdown(Path.of("handbook.docx"),
ConvertToMarkdownOptions.builder().saveTo("handbook.md").build());
Akzeptiert PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT und MD sowie ältere und ODF-Office-Formate. Das Format wird serverseitig erkannt, es gibt also keine clientseitige Prüfung der Erweiterung: Jede Datei wird unverändert hochgeladen. Bilder werden nicht unterstützt und mit 400 abgelehnt. Die einzigen Optionen sind saveTo und outputFilename.
convertToPdf#
Der andere automatisch erkennende Endpunkt: fast alles zu PDF.
// pptx zu pdf
client.convertToPdf(Path.of("slides.pptx"),
ConvertToPdfOptions.builder().saveTo("slides.pdf").build());
// pdf-Durchreichung, in Graustufen umgewandelt
client.convertToPdf(Path.of("scan.pdf"),
ConvertToPdfOptions.builder()
.pdfOptions(PdfOptions.builder().grayscale(true).build())
.saveTo("scan-gray.pdf")
.build());
Akzeptiert Office, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, reinen Text, Rasterbilder, SVG, EPUB und ein bestehendes PDF als Durchreichung. EPUB wird hier behandelt, weil es kein eigenes Dokumentpaar hat. Die Optionen sind saveTo, outputFilename und pdfOptions.
grayscale wird an diesem Endpunkt berücksichtigt. Die Seitengeometrie (Seitengröße, Breite und Höhe, Ausrichtung, Ränder, Skalierung, Kopfzeile, Fußzeile) wird von anything-to-pdf ignoriert. Wenn du die vollständige Seiteneinrichtung brauchst, nimm stattdessen convertDocument oder convertUrlToPdf.
Konvertierung ganzer Websites#
convertWebsiteToPdf und convertWebsiteToScreenshot ermitteln jede Seite einer Website, konvertieren jede einzelne im Hintergrund und bündeln die Ergebnisse in einem einzigen ZIP. Beide arbeiten asynchron und geben ein BatchSubmission zurück. Beide benötigen einen privaten API-Key.
BatchSubmission batch = client.convertWebsiteToPdf("https://example.com",
WebsiteToPdfOptions.builder()
.crawlMode("sitemap") // "auto" (Standard), "sitemap", "full"
.excludePatterns(List.of("/blog/tag/")) // nur im Full-Crawl-Modus
.notificationEmail("[email protected]")
.build());
System.out.println(batch.batchId() + " " + batch.urlCount() + " " + batch.discoveryMethod());
// Blockiert, bis der Batch "processing" verlässt, dann das ZIP speichern
BatchStatus status = client.waitForBatch(batch.batchId(),
WaitForBatchOptions.builder().saveTo("site.zip").build());
System.out.println(status.completed() + " of " + status.total() + " pages converted");
convertWebsiteToScreenshot funktioniert identisch und erzeugt ein ZIP mit PNGs. waitForBatch fragt standardmäßig alle 5 Sekunden ab, gibt nach 30 Minuten auf und akzeptiert intervalMs, timeoutMs und saveTo. Bei Zeitüberschreitung wirft es eine ApiException mit Status 504.
Status selbst abfragen#
JobStatus job = client.getJobStatus("job_abc123");
if ("success".equals(job.status())) System.out.println(job.presignedUrl());
if ("failed".equals(job.status())) System.err.println(job.error());
BatchStatus batch = client.getBatchStatus("bat_abc123");
if (!"processing".equals(batch.status())) System.out.println(batch.zipDownloadUrl());
Web-Intelligence (V2)#
Alles unter client.v2 verwandelt Webseiten in agentenfertige Daten. Jeder Lesevorgang trägt renderQuality, einen Wert von 0.0 bis 1.0, der angibt, wie sauber die Seite tatsächlich gerendert wurde. Eine Challenge-Seite, eine Cookie-Wall oder eine leere SPA-Hülle kommt mit niedrigem Wert sowie gefüllten warnings() und deductions() zurück, statt als echter Inhalt durchzugehen. So gelangt ein schlechter Lesevorgang nie unbemerkt in den Kontext deines Agenten. Der Inhalt wird trotzdem zurückgegeben, er ist lediglich markiert. Hintergründe zum Modell findest du in der V2-Übersicht.
Perceive#
Rendere eine URL in genau die Artefakte, die du anforderst. Endpunkt-Referenz: Perceive.
PerceiveResult page = client.v2.perceive("https://example.com",
PerceiveOptions.builder()
.outputs(List.of("markdown", "screenshot", "structured"))
.extract(List.of("tables", "metadata"))
.waitFor("css:main")
.build());
System.out.println(page.renderQuality()); // 0.0 bis 1.0
System.out.println(page.statusCode() + " " + page.deductions()); // z. B. 200 {http_error=0.7}
System.out.println(page.outputs().get("markdown").url()); // signierte URL, 15 Minuten
System.out.println(page.structured()); // vom Aufrufer definierte Struktur
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
outputs |
List<String> |
["markdown", "structured"] |
Beliebige aus markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
List<String> |
keiner | Heuristische Ziele: tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
schema |
Map<String, Object> |
keiner | JSON-Schema für die strukturierte Extraktion. |
waitFor, waitTimeoutMs |
String, int |
keiner, 30000 |
Ein CSS-Selektor, optional mit dem Präfix css:, oder js:<expr>, auf den gewartet wird, mit einem Budget von 0 bis 60000 ms. |
jsCode |
String |
keiner | JavaScript, das nach der Navigation ausgeführt wird, maximal 20000 Zeichen. |
viewport, mobile |
PerceiveViewport, boolean |
1920 x 1080, false |
Breite 320 bis 3840, Höhe 240 bis 2160, oder Mobile-Emulation. |
onlyMainContent |
boolean |
true |
Entfernt Navigation, Header, Footer und Cookie-Banner aus dem Markdown-Artefakt und dem main_content-Extrakt. |
cacheMode |
String |
"enabled" |
enabled nutzt einen Cache von 1 Stunde erneut, bypass überspringt ihn, refresh erzwingt ein erneutes Rendern. |
blockResources |
List<String> |
keiner | Ressourcentypen, die der Browser nicht laden soll, zum Beispiel image, font, script. |
pdfOptions |
PdfOptions |
keiner | Nur sinnvoll, wenn outputs den Wert pdf enthält. |
headers, cookies, auth |
Map, List<BrowserCookie>, HttpBasicAuth |
keiner | Request-Header, eingeschleuste Cookies, HTTP-Basic-Zugangsdaten. |
respectRobots |
boolean |
keiner | Berücksichtigt die Robots-Regeln der Website. |
proxyUrl, geolocation und actionChain existieren im Builder, sind serverseitig aber nicht verfügbar und werden derzeit mit 422 abgelehnt.
Artefakt-URLs sind 15 Minuten lang signiert und werden bei jedem Lesen der Operation neu signiert, client.v2.getPerceiveOperation(page.operationId()) liefert dir also frische Links. Bündle bis zu 1000 URLs mit einem gemeinsamen Options-Block: Kleine Batches werden inline fertig, größere kommen mit dem Status queued zurück, frage sie also ab.
PerceiveBatchResult batch = client.v2.perceiveBatch(
List.of("https://a.example.com", "https://b.example.com"),
PerceiveBatchOptions.builder()
.outputs(List.of("markdown"))
.outputMode("zip") // "manifest" (Standard) oder "zip"
.build());
PerceiveBatchResult done = client.v2.getPerceiveBatch(batch.jobId());
System.out.println(done.completed() + "/" + done.total());
Überspringe den Umweg über die signierte URL vollständig mit perceiveDirect, das die Artefakt-Bytes zurückstreamt. Es benötigt genau eine artefakterzeugende Ausgabe (alles außer structured) und wirft vor dem Senden eine IllegalArgumentException, wenn du mehr oder weniger anforderst:
PerceiveDirectResult direct = client.v2.perceiveDirect("https://example.com",
PerceiveOptions.builder().outputs(List.of("pdf")).build());
Files.write(Path.of(direct.filename()), direct.content());
System.out.println(direct.renderQuality() + " " + direct.contentType());
// Ein gespeichertes Artefakt einer früheren Operation erneut herunterladen
PerceiveDirectResult stored = client.v2.downloadPerceiveArtifact(page.operationId(), "markdown");
downloadPerceiveArtifact akzeptiert einen null-Wert oder einen weggelassenen Ausgabenamen, wenn die Operation genau ein Artefakt erzeugt hat, andernfalls gibt es 400 zurück und listet die verfügbaren Ausgaben auf. Sobald das gespeicherte Artefakt abgelaufen ist, gibt es 410 zurück.
Discover#
Zähle die URLs einer Website auf, ohne irgendetwas zu rendern. Es ist kein Browser beteiligt, daher ist es schnell. Endpunkt-Referenz: Discover.
DiscoverResult found = client.v2.discover("https://example.com",
DiscoverOptions.builder()
.mode("hybrid") // "sitemap", "crawl", "hybrid"
.maxUrls(200)
.maxDepth(3)
.excludePatterns(List.of("/tag/"))
.build());
System.out.println(found.total() + " urls, truncated=" + found.truncated());
found.urls().forEach(System.out::println);
| Option | Typ | Standard | Bereich |
|---|---|---|---|
mode |
String |
"hybrid" |
sitemap, crawl, hybrid |
maxUrls |
int |
100 |
1 bis 1000 |
maxDepth |
int |
2 |
1 bis 5 |
includePatterns, excludePatterns |
List<String> |
keiner | Regex-Positivliste und Sperrliste, jeweils maximal 50 Einträge. Die Sperrliste wird als zweites angewendet. |
sameDomainOnly, respectRobots |
boolean |
true, keiner |
Auf der Ausgangsdomain bleiben und die Robots-Regeln der Website berücksichtigen. |
Lookup#
Kategorisierte Websuche, die die besten Treffer auf Wunsch automatisch rendert. Endpunkt-Referenz: Lookup.
LookupResult search = client.v2.lookup("best static site generators",
LookupOptions.builder()
.category("web") // web, news, images, scholar, patents, maps
.numResults(10)
.country("us")
.timeFilter("month") // hour, day, week, month, year
.perceiveTop(3) // die 3 besten Treffer automatisch rendern
.build());
search.results().forEach(hit -> {
System.out.println(hit.position() + " " + hit.title() + " " + hit.url());
if (hit.perceive() != null) System.out.println(" quality " + hit.perceive().renderQuality());
});
Mit perceiveTop über 0 (0 bis 10, Standard 0) werden die URLs der ersten N Treffer über perceive gerendert, und jeder Treffer trägt sein vollständiges PerceiveResult inline auf hit.perceive(). numResults läuft von 1 bis 100 und ist standardmäßig 10; page läuft von 1 bis 10.
Distill#
Schemagesteuerte strukturierte Extraktion über eine oder mehrere Seiten. Endpunkt-Referenz: Distill.
DistillResult extraction = client.v2.distill(
DistillOptions.builder(Map.of("products", "list of product names with their listed price"))
.urls(List.of("https://example.com/catalog"))
.cssSchema(CssSchema.builder(".product-card", List.of(
CssField.builder("name", "text").selector("h3").build(),
CssField.builder("price", "text").selector(".price").build()))
.targetField("products")
.build())
.build());
extraction.results().forEach(item ->
System.out.println(item.data() + " via " + item.extractionTier()));
Das optionale cssSchema führt zuerst einen kostenlosen CSS-Durchlauf aus; nur die Felder, die es nicht beantworten kann, steigen in die LLM-Stufe auf, und item.extractionTier() meldet, welcher Weg den Datensatz erzeugt hat (css, llm, mixed oder none). Du kannst die URLs auch zuerst ermitteln lassen, statt sie aufzulisten:
client.v2.distill(
DistillOptions.builder(Map.of("title", "page title", "summary", "one-line summary"))
.discoverFrom(new DistillDiscoverFrom("https://example.com", "sitemap", 10))
.build());
Genau eines von urls (maximal 50) und discoverFrom muss gesetzt sein, und schema ist von der Builder-Factory vorgeschrieben. Beide Regeln werden clientseitig geprüft und werfen eine IllegalArgumentException, bevor eine Anfrage rausgeht.
Ingest#
Verwandle eine ganze Website oder einen Satz hochgeladener Dokumente über eine einzige Pipeline in gechunktes, RAG-fertiges JSONL. Ingest arbeitet immer asynchron. Endpunkt-Referenz: Ingest.
// Von einer Website
IngestJob job = client.v2.ingest(IngestOptions.builder()
.mode("sitemap") // "urls" (Standard), "sitemap", "crawl"
.url("https://docs.example.com")
.maxPages(100)
.chunk(new IngestChunkOptions(512, 1)) // maxWords, sentenceOverlap
.webhookUrl("https://my.app/hooks/enconvert")
.build());
// Oder aus hochgeladenen Dateien
IngestJob fileJob = client.v2.ingestFiles(
List.of(new FileInput(Files.readAllBytes(Path.of("handbook.pdf")), "handbook.pdf"),
new FileInput(Files.readAllBytes(Path.of("notes.docx")), "notes.docx")),
IngestFilesOptions.builder().chunk(new IngestChunkOptions(512, 1)).build());
// Auf das JSONL pollen
IngestJob status = client.v2.getIngestJob(job.jobId());
if ("completed".equals(status.status())) {
System.out.println(status.outputUrl() + " (" + status.totalChunks() + " chunks)");
}
client.v2.listIngestJobs(V2ListOptions.builder().limit(20).build());
client.v2.cancelIngestJob(job.jobId()); // idempotent
ingestFiles akzeptiert PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT und MD sowie ältere und ODF-Office-Formate. Das Chunking liegt standardmäßig bei 512 Wörtern (32 bis 4000) mit 1 Satz Überlappung (0 bis 10). mode ist standardmäßig urls, was eine nicht leere urls-Liste verlangt und url verbietet; jeder andere Modus verlangt eine Start-url und verbietet urls. Das SDK erzwingt diese Paarung vor dem Senden.
Abschluss-Webhooks sind HMAC-signiert. Hole dir das Secret und die Header-Namen, die du zur Verifikation einer Zustellung brauchst, rotiere es bei einem Leck und stoße eine Zustellung neu an, die dein Endpunkt verpasst hat:
WebhookSecret secret = client.v2.getWebhookSecret();
System.out.println(secret.signatureHeader() + " " + secret.signatureScheme());
client.v2.rotateWebhookSecret(); // alte Signaturen verifizieren sofort nicht mehr
WebhookRetryResult retry = client.v2.retryIngestWebhook(job.jobId());
System.out.println(retry.delivered() + " after " + retry.attempts() + " attempts");
Watch#
Wiederkehrende Änderungsüberwachung einer URL, mit Benachrichtigung per E-Mail und Webhook. Endpunkt-Referenz: Watch.
Watcher watcher = client.v2.createWatcher("https://example.com/pricing",
WatchCreateOptions.builder()
.frequencyMinutes(60) // 60 bis 43200, Untergrenze eine Stunde
.diffMode("auto") // auto, text, structured, tables, metadata
.webhookUrl("https://my.app/hooks/changes")
.notifyEmail(true)
.build());
WatcherSnapshotList history = client.v2.getWatcherSnapshots(watcher.watcherId(),
SnapshotListOptions.builder().limit(10).build());
history.snapshots().forEach(s ->
System.out.println(s.checkedAt() + " changed=" + s.hasChanges()
+ " similarity=" + s.similarity()));
client.v2.updateWatcher(watcher.watcherId(), WatcherUpdate.builder().status("paused").build());
client.v2.updateWatcher(watcher.watcherId(), WatcherUpdate.builder().webhookUrl("").build());
client.v2.deleteWatcher(watcher.watcherId()); // Soft Delete, idempotent
listWatchers() und getWatcher(watcherId) lesen sie wieder aus. updateWatcher verlangt mindestens ein Feld und wirft andernfalls eine IllegalArgumentException. Ein ausdrücklich leerer String für webhookUrl löscht den Webhook, während ein null-Wert "keine Änderung" bedeutet. deleteWatcher ist ein Soft Delete: Es gibt den als gelöscht markierten Watcher mit Status deleted zurück, und ein gelöschter Watcher liest sich danach als 404.
WatcherSnapshot.changes() ist Rohtext, der aus der überwachten Seite stammt. Escape ihn, bevor du ihn in einem Dashboard, einer E-Mail oder einer Chat-Nachricht darstellst.
PDF-Optionen#
PdfOptions wird von convertUrlToPdf, convertWebsiteToPdf, convertDocument, convertToPdf und PerceiveOptions.pdfOptions gemeinsam genutzt.
client.convertUrlToPdf("https://internal.example.com/report",
UrlToPdfOptions.builder()
.pdfOptions(PdfOptions.builder()
.pageSize("A4")
.orientation("landscape")
.margins(new PdfMargins(10.0, 10.0, 15.0, 15.0))
.scale(0.9)
.header(new PdfHeaderFooter("Quarterly Report", 15.0))
.footer(new PdfHeaderFooter("Confidential", 12.0))
.build())
.auth(new HttpBasicAuth("user", "pass"))
.cookies(List.of(BrowserCookie.builder("session", "abc123").domain("internal.example.com").build()))
.headers(Map.of("X-Tenant", "acme"))
.saveTo("report.pdf")
.build());
| Feld | Typ | Beschreibung |
|---|---|---|
pageSize |
String |
"A4", "A3", "Letter", "Legal" und Ähnliches. |
pageWidth, pageHeight |
double |
Eigene Maße. Gemeinsam gesetzt überschreiben sie pageSize. |
orientation |
String |
"portrait" oder "landscape". |
margins |
PdfMargins |
Record aus top, bottom, left, right. Jedes null-Feld wird weggelassen. |
scale |
double |
Render-Skalierung, zum Beispiel 0.9 für 90 Prozent. |
grayscale |
boolean |
Wandelt das PDF nachträglich in Graustufen um. |
header, footer |
PdfHeaderFooter |
Record aus content (maximal 2000 Zeichen) und height. |
BrowserCookie braucht Name und Wert sowie entweder domain oder url; wenn domain ohne path gesetzt ist, setzt die API path standardmäßig auf /. Kombiniere auth nicht mit einem expliziten Authorization-Header, denn die API lehnt diesen Konflikt ab.
Fehlerbehandlung#
Jede SDK-Exception erbt von EnconvertException, das wiederum von RuntimeException erbt, nichts erzwingt an deinen Aufrufstellen also eine throws-Klausel. Fange die spezifischen Unterklassen zuerst ab.
try {
client.convertUrlToPdf("https://example.com");
} catch (AuthenticationException e) {
System.err.println("Invalid or missing API key");
} catch (QuotaException e) {
System.err.println("Request refused with 402: " + e.getMessage());
} catch (RateLimitException e) {
System.err.println("Too many requests, back off and retry");
} catch (ApiException e) {
System.err.println("API error [" + e.getStatusCode() + "]: " + e.getMessage());
}
| Klasse | Ausgelöst bei | Statuscode |
|---|---|---|
AuthenticationException |
Fehlender, ungültiger oder nicht berechtigter API-Key | 401, 403 |
QuotaException |
HTTP 402 | 402 |
RateLimitException |
Zu viele Anfragen | 429 |
ApiException |
Jede andere 4xx- oder 5xx-Antwort | der tatsächliche Code |
EnconvertException |
Basisklasse, wird auch bei Transportfehlern, einer unterbrochenen Anfrage oder einer nicht lesbaren Eingabedatei ausgelöst | keiner |
Clientseitige Validierung (ein nicht unterstütztes Konvertierungspaar, ein fehlendes distill-Schema, ein leeres Watcher-Update, die falsche Anzahl Ausgaben für perceiveDirect) wirft eine IllegalArgumentException, bevor eine Anfrage gestellt wird. Die Zuordnung der Meldungen für Serverantworten findest du in der Referenz Fehlercodes.
Timeout-Recovery#
Lange URL-Renders und große Dokumentkonvertierungen können das Reverse-Proxy-Timeout überdauern, selbst wenn die Konvertierung am Ende erfolgreich ist. Das SDK behandelt das transparent:
- Vor jeder Anfrage für eine einzelne URL oder einen Datei-Upload erzeugt das SDK eine UUID und sendet sie als
job_id. - Kommt die Anfrage mit 5xx zurück, wechselt das SDK dazu,
GET /v1/convert/status/{jobId}alle 3 Sekunden abzufragen. - Bei
successgibt es das Ergebnis zurück. Beifailedwirft es eineApiExceptionmit der Fehlermeldung des Servers. - Die Polling-Frist beträgt 5 Minuten. Danach wirft es
ApiException(504, "Conversion timed out").
Du schreibst dafür keinen Code. Wenn eine erfolgreiche Antwort job_id weglässt, trägt das SDK die selbst erzeugte ID nach, result.jobId() ist also immer mit getJobStatus verwendbar.
convertWebsiteToPdf und convertWebsiteToScreenshot haben keine Job-Zeile zum Abfragen, ein 5xx bedeutet dort also, dass die Übermittlung selbst fehlgeschlagen ist, und wird direkt gemeldet. V2-Endpunkte nutzen ebenfalls kein Job-Polling; ihre asynchronen Abläufe laufen über getPerceiveBatch und getIngestJob.
Konfiguration#
Enconvert client = Enconvert.builder(System.getenv("ENCONVERT_API_KEY"))
.baseUrl("https://api.enconvert.com")
.timeout(Duration.ofSeconds(300))
.build();
Drei Konstruktoren stehen als Kurzform bereit: new Enconvert(apiKey), new Enconvert(apiKey, baseUrl) und new Enconvert(apiKey, baseUrl, timeout).
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
apiKey |
String |
erforderlich | Privater API-Key. Ein null-Wert oder leerer Wert wirft eine IllegalArgumentException. |
baseUrl |
String |
https://api.enconvert.com |
Basis-URL der API. Abschließende Schrägstriche werden entfernt. |
timeout |
Duration |
300 Sekunden | Gilt sowohl als Verbindungs-Timeout als auch als Timeout pro Anfrage. |
Der Key reist im Header X-API-Key. Vorsignierte Download-URLs werden ohne ihn abgerufen, da sie bereits signiert sind. Key-Typen behandelt die Authentifizierung; Keys erstellst und verwaltest du im Dashboard.
Ergebnisform#
Jede Konvertierung einer einzelnen Datei oder einer einzelnen URL gibt dasselbe Record zurück:
public record ConversionResult(
String presignedUrl,
String objectKey,
String filename,
Long fileSize,
Double conversionTimeSeconds,
String jobId) {}
Die vorsignierte URL ist zeitlich begrenzt. Übergib saveTo (oder rufe die URL selbst ab) und speichere die Bytes in deinem eigenen Bucket, wenn sie diese Frist überdauern sollen.
Die anderen Antwort-Records, mit denen du am häufigsten zu tun hast:
| Record | Wichtige Accessoren |
|---|---|
JobStatus |
status() (processing, success, failed), presignedUrl(), objectKey(), error() |
BatchStatus |
status(), total(), completed(), failed(), inProgress(), zipDownloadUrl(), items() |
PerceiveResult |
operationId(), renderQuality(), statusCode(), deductions(), outputs(), structured(), cacheHit(), warnings() |
V2OutputArtifact |
url(), objectKey(), sizeBytes(), contentType(), expiresIn() |
PerceiveDirectResult |
content(), contentType(), filename(), renderQuality(), contentHash() |
IngestJob |
jobId(), status(), pagesProcessed(), totalChunks(), outputUrl(), webhookDelivered() |
Watcher |
watcherId(), status(), frequencyMinutes(), checksCount(), nextCheckAt(), lastChangeAt() |
Felder, deren Struktur durch deine eigene Anfrage bestimmt wird (structured, data, trackFields, Snapshot-changes), werden als Gson-JsonObject bereitgestellt und unverändert durchgereicht. Zeichenketten-basierte Aufzählungen bleiben String und werden nicht zu Java-enum-Konstanten, ein neuerer API-Wert bricht also nie die Deserialisierung in einem älteren SDK-Build. com.enconvert.model.v2.V2Enums enthält jeden akzeptierten Wert als tippfehlersichere Konstante.
Quelle und Issues#
- Maven Central:
com.enconvert:enconvert-sdk:0.0.1 - GitHub: conversionapi/java-sdk
- Lizenz: MIT
- Weitere Clients: alle SDKs · Endpunkt-Referenz · Preise
Häufig gestellte Fragen#
Wie konvertiere ich Dateien in Java mit einer Maven-Abhängigkeit?#
Füge com.enconvert:enconvert-sdk:0.0.1 zu deiner pom.xml oder build.gradle hinzu, baue einen Client mit new Enconvert(System.getenv("ENCONVERT_API_KEY")) und rufe eine typisierte Methode wie convertUrlToPdf, convertImage, convertDocument oder convertToPdf auf. Übergib saveTo im Options-Builder, um die Ausgabe direkt auf die Festplatte zu schreiben, statt die vorsignierte URL selbst zu verarbeiten.
Wie konvertiere ich eine URL in Java in ein PDF?#
Rufe client.convertUrlToPdf(url, UrlToPdfOptions.builder().saveTo("page.pdf").build()) auf. Setze singlePage(false), um anhand von pdfOptions.pageSize zu paginieren, statt eine einzige fortlaufende Seite zu erzeugen, und übergib auth, cookies oder headers für eine Seite hinter einem Login.
Wie konvertiere ich DOCX in Java in ein PDF?#
Rufe client.convertDocument(Path.of("report.docx"), ConvertDocumentOptions.builder().saveTo("report.pdf").build()) auf. Das Ausgabeformat ist standardmäßig pdf, du setzt outputFormat also nur, wenn du etwas anderes willst, zum Beispiel yaml aus einer .json-Eingabe. Für Formate ohne eigenes Paar, etwa EPUB oder RTF, nimm convertToPdf.
Wie konvertiere ich HEIC in Java in WebP?#
Rufe client.convertImage(Path.of("photo.heic"), ConvertImageOptions.builder("webp").saveTo("photo.webp").build()) auf. Das Eingabeformat ergibt sich aus der Dateiendung, und das Ausgabeformat ist das erforderliche Builder-Argument. jpeg, png, svg, heic und webp konvertieren alle untereinander, und pdf wird zu jpeg gerastert. Eine Methode zum Komprimieren an Ort und Stelle gibt es in diesem Client nicht.
Wie scrape ich aus Java eine Webseite in sauberes Markdown?#
Es gibt zwei Wege. client.convertUrlToMarkdown(url, ...) liefert GitHub Flavored Markdown mit YAML-Frontmatter als herunterladbare Datei. client.v2.perceive(url, PerceiveOptions.builder().outputs(List.of("markdown")).build()) liefert denselben Inhalt als agentenfertiges Artefakt mit einem renderQuality-Wert, Extraktionsoptionen und Cache-Steuerung. Nimm perceive, wenn ein schlechter Lesevorgang erkennbar sein muss statt still zu bleiben.
Was ist renderQuality und warum trägt jeder Lesevorgang einen Wert?#
renderQuality ist ein Wert von 0.0 bis 1.0, der an jedem V2-Render hängt. Ein hoher Wert bedeutet, dass die Seite sauber gerendert wurde; ein niedriger Wert bedeutet, dass etwas dazwischenkam, etwa eine Bot-Challenge, eine Cookie-Wall, ein Login-Bildschirm, eine HTTP-Fehlerseite oder eine leere SPA-Hülle. Der Inhalt wird trotzdem zurückgegeben, mit gefüllten warnings() und deductions(), sodass deine Pipeline den Lesevorgang verwerfen oder wiederholen kann, statt eine Challenge-Seite so an ein Modell zu geben, als wäre sie der Artikel.
Wie verwandle ich eine Doku-Website in Java in RAG-fertige Chunks?#
Rufe client.v2.ingest(IngestOptions.builder().mode("sitemap").url("https://docs.example.com").maxPages(100).chunk(new IngestChunkOptions(512, 1)).build()) auf. Der Job ist asynchron, frage also entweder getIngestJob(jobId) ab, bis der Status completed lautet, und lies outputUrl() für das JSONL, oder setze webhookUrl und verifiziere die HMAC-Signatur mit dem Secret aus getWebhookSecret(). Für lokale Dokumente statt einer Website nimm ingestFiles.
Wie geht das SDK mit Konvertierungen um, die das Proxy-Timeout überdauern?#
Vor jeder Anfrage für eine einzelne URL oder einen Datei-Upload erzeugt es eine UUID und sendet sie als job_id. Gibt die Anfrage 5xx zurück, fragt es GET /v1/convert/status/{jobId} alle 3 Sekunden ab, bis der Job success oder failed meldet, mit einer Frist von 5 Minuten, nach der es ApiException(504, "Conversion timed out") wirft. Batch-Übermittlungen für ganze Websites sind ausgenommen, weil sie keine Job-Zeile zum Abfragen haben.
Welche Java-Version verlangt das SDK, und was zieht es nach?#
Java 17 oder neuer. HTTP läuft über den java.net.http.HttpClient des JDK, und Gson ist das einzige Drittanbieter-Artefakt auf dem Classpath. Antworten sind Java-Records, ein modernes switch oder Pattern-Matching darüber funktioniert also wie erwartet. Der Client ist threadsicher: Halte eine Instanz und teile sie.