API-Dokumentation

Ein Endpunkt. Formatversion 4. Basis-URL https://api.consensis.app.

Authentifizierung

Jede Anfrage trägt einen API-Schlüssel — Authorization: Bearer pk_live_… oder den Header X-API-Key. Melden Sie sich an (Google oder E-Mail; die Anmeldung legt das Konto an) und stellen Sie Schlüssel auf Ihrer Kontoseite aus. Der Klartextschlüssel wird einmalig angezeigt; wir speichern nur einen Digest. Ein Schlüssel, den wir nicht zuordnen können, liefert 401 — ein vertippter Schlüssel wird nie stillschweigend auf den anonymen Test herabgestuft, Sie wissen also immer, welchem Konto ein Auftrag berechnet wurde.

Anonymer Test: 10 kostenlose Seiten pro Tag und Adresse über die API — und weitere 10 pro Tag über den Web-Uploader — ohne Konto. Bezahlte Nutzung ist Prepaid — 0.06 pro gelieferter Seite (0.036 mit mode=batch), Mindestaufladung 3.50. Fehlgeschlagene Seiten werden nie berechnet.

Kostenlos ausprobieren — ohne Schlüssel, ohne Konto

Der kostenlose Test funktioniert direkt über die API: 10 kostenlose Seiten pro Tag und Adresse, ganz ohne Authorization-Header (der Web-Uploader hat seine eigenen 10; jenseits des Kontingents trägt die Antwort Retry-After).

# vollständig anonym — kein Schlüssel, keine Registrierung
curl -X POST https://api.consensis.app/v1/parse -F "[email protected]"
# → 202 {"id": "…", "status": "queued", ...} — abfragen wie unten beschrieben

Drei Zeilen zum Start

curl -X POST https://api.consensis.app/v1/parse \
     -H "Authorization: Bearer pk_live_…" \
     -F "[email protected]" -F "pages=10"
# → 202 {"id": "b7f395cf7fbc", "status": "queued", ...}

curl -H "Authorization: Bearer pk_live_…" \
     https://api.consensis.app/v1/parse/b7f395cf7fbc
# → abfragen bis "status": "done", dann sind usage und result enthalten

curl -OJ -H "Authorization: Bearer pk_live_…" \
     "https://api.consensis.app/v1/parse/b7f395cf7fbc/export?format=xlsx"
Exportformat wählen: json und zip enthalten alles (Konfidenz, Quellen, Lesungen, bbox); xlsx hält die Konfidenzmarkierungen sichtbar — strittige Zellen rot hinterlegt, nicht verifizierte gelb — plus ein flaches cells-Blatt für die Prüfung; csv enthält nur Werte: Es kann nicht ausdrücken, welche Zellen strittig sind, kombinieren Sie es also mit dem JSON, wenn Vertrauen zählt.

Asynchron — POST liefert sofort 202; fragen Sie mit der id nach. 10 Seiten brauchen aus dem Kaltstart ≈600 s; Cache-Treffer sind deutlich schneller. Leiten Sie den Abschluss nicht aus stage ab — dieser String ist für Menschen; beobachten Sie status.

Batch-Modus — 0.036/Seite: Fügen Sie dem POST -F "mode=batch" hinzu. Dieselbe Extraktion, dieselben Garantien, dieselbe Ergebnisform; der Unterschied ist die Zeit — ein Lesezweig läuft über einen Batch-Endpunkt. Gemessen 4–55 Minuten über neun Läufe, aber das ist eine Beobachtung, kein Versprechen: Der vorgelagerte Batch-Dienst zielt auf 24 Stunden und sagt das auch. Was wir versprechen, ist eine Untergrenze — ist der Batch-Zweig nach 4 Stunden nicht zurück, führen wir ihn auf der Echtzeit-Pipeline erneut aus, und Sie bekommen Ihr Ergebnis trotzdem, weiterhin zum Batch-Preis. Die Differenz tragen wir. Abfrage wie gewohnt; der Auftrag meldet "mode": "batch". Wählen Sie ihn für Nachtläufe und große Nachverarbeitungen, bei denen der Preis über der Latenz steht.

Was jede Zelle trägt

Das ist es, was die API verkauft. Nicht „bessere Extraktion“ — jede Zelle kann für sich selbst Rechenschaft ablegen.

{"value": "1432",
 "confidence": "verified",
 "sources": ["vision-1", "vision-2"],
 "bbox": [436.5, 577.7, 459.8, 591.9]}

Zwei unabhängige Lesungen stimmten überein, die Zelle ist also verified und trägt keine readings — der Wert ist der Wert.

readings ist der entscheidende Unterschied: Wenn Lesungen abweichen, bekommen Sie jede Version — wir wählen nicht stillschweigend eine aus. Wäre die Wahl falsch, hätten Sie keinen Anhaltspunkt, wo Sie hinschauen sollen. Nur vorhanden, wenn es eine Abweichung gibt:

{"value": "1432",
 "confidence": "disputed",
 "provisional": true,
 "sources": ["vision-1", "vision-2"],
 "readings": {"vision-1": "1432", "vision-2": "1482"}}

provisional

Erscheint nur, wenn confidence gleich disputed ist, und ist immer true.

Wenn Quellen abweichen, liefern wir trotzdem einen Wert — Daten müssen nutzbar sein, und eine leere Zelle ist ein stillschweigend verlorener Wert. Aber dieser Wert ist vorläufig: Prüfen Sie ihn gegen readings, bevor Sie danach handeln, und importieren Sie ihn nicht direkt in ein Produktivsystem.

confidence

confidenceBedeutung
exactdirekt aus einer strukturierten Datei gelesen — ohne jede Interpretation
verifiedmehrere unabhängige Lesungen stimmen überein
confirmedvon einem Menschen mit Blick auf die Originalseite entschieden
reviewedvom KI-Prüfer anhand des Original-Seitenbilds entschieden — schnell und abgewogen, aber nicht unabhängig verifiziert
resolvedeine Mehrheit der Lesungen stimmt überein
unverifiednur eine Lesung vorhanden — nichts zum Gegenprüfen
disputedunabhängige Lesungen weichen voneinander ab — diese Zellen brauchen einen Menschen

sources

Das sind keine Anbieternamen. Eine Prüfung fragt „wie viele unabhängige Lesungen“, nicht „welcher Anbieter“.

sourcesWas es ist
ocr-1eine OCR-Engine aus einer Modellfamilie
ocr-2eine OCR-Engine aus einer anderen Familie — nur verschiedene Familien können Verzerrungen aus derselben Quelle auffangen
ocr-3eine dritte OCR-Familie. Im aktuellen Dienst nicht aktiviert — der Name bleibt im Vokabular, weil sich der Vertrag nicht ändern sollte, wenn sich unsere Konfiguration ändert.
pdf-layoutdie eigene Layout-Geometrie des PDFs (am genauesten — und kostenlos —, wenn Linien und eine Textebene vorhanden sind)
pdf-gridRasterlinien, aus gefüllten Rechtecken abgeleitet
pdf-modelein trainiertes Layout-Modell, das die interne Struktur des PDFs liest — keine OCR, keine Abhängigkeit von Linien
pdf-textdie Textebene des PDFs
source-datadirekt aus einer strukturierten Datei gelesen (XLSX/CSV — keine Interpretation)
vision-reviewgegen das Originalbild der Seite entschieden
layoutdie Layout-Lesung hat an dieser Position eine Abbildung gefunden
ocreine zweite Lesung hat unabhängig eine Abbildung gefunden, die denselben Rahmen überlappt — das ist die, die ein Bild verified macht
pdf-imagedas PDF selbst hat hier ein eingebettetes Bildobjekt. Für sich genommen ist das keine zweite Meinung — es sagt, dass die Datei ein Bild enthält, nicht, dass wir das richtige eingerahmt haben
vision-1einer von zwei unabhängigen Vision-Lesern, die jeweils das Seitenbild betrachten und das Tabellenraster rekonstruieren
vision-2der zweite Vision-Leser — eine andere Modellfamilie als vision-1, damit die beiden unabhängig voneinander abweichen können
vision-singleper Vision gelesen, aber für diese Zelle existiert nur eine Lesung — keine zweite Meinung hat sie bestätigt
vision-auditconfirmed by the audit pass — a separate reading of the original page image that reviewed the whole table and raised no objection to this cell.
vision-arbitereine zusätzliche Lesung, die eine Abweichung zwischen den beiden Vision-Lesern entschieden hat — keiner der beiden
vision-gridwiederhergestellt durch erneutes Lesen des Seitenbilds zum Neuaufbau des Rasters, wo der erste Durchgang Lücken oder eine verschobene Zeile hinterlassen hat
human-reviewvon einem Menschen auf der Prüfseite mit Gegenüberstellung geprüft — jede andere Quelle interpretiert die Seite; diese ist eine Person, die sie bestätigt oder korrigiert

bbox

[x0, y0, x1, y1] in PDF-Punkten (1/72 Zoll), Ursprung oben links; die Seitenzahl steht in page der Tabelle.

Die Abdeckung ist nicht 100% und schwankt stark je Dokument (gemessen 3%–48%). usage.cells_with_bbox meldet genau, wie viele Zellen Ihres Dokuments eine haben — die Zahl wird nicht versteckt.

Wie eine Tabelle aussieht

Der Abschnitt oben sagt, was eine Zelle trägt. Dieser sagt, wie eine Tabelle um sie herum geformt ist.

{
 "page": 7,
 "index": 0,
 "order": null,
 "kind": null,
 "layout_disputed": true,
 "column_major": false,
 "header": [
  "model",
  "d"
 ],
 "row_groups": [],
 "header_cells": [
  {
   "value": "model",
   "confidence": "unverified",
   "sources": []
  },
  {
   "value": "d",
   "confidence": "unverified",
   "sources": []
  }
 ],
 "rows": [
  [
   {
    "value": "LB 08",
    "confidence": "unverified",
    "sources": []
   },
   {
    "value": "1432",
    "confidence": "verified",
    "sources": [
     "vision-1",
     "vision-2"
    ]
   }
  ]
 ]
}

header sind die reinen Spaltennamen — abgeleitet aus header_cells, nie getrennt berechnet, die beiden können also nicht auseinanderdriften. header_cells sind dieselben Namen mit angehängter confidence und sources: Ein falscher Spaltenname lässt die ganze Spalte etwas anderes bedeuten, und man sieht es ihr nicht an.

rows ist eine Liste von Zeilen, jede eine Liste von Zellen. column_major sagt Ihnen, ob die Quelltabelle quer oder abwärts lief; wir liefern immer Zeilen, dies hält fest, was die Seite tat.

row_groups ist die gedrehte seitliche Klassifikation, die Sie auf Spezifikationstabellen sehen (Abmessungen (mm), Tragzahl) — eine Beschriftung pro Zeile. Es ist keine Spalte, weil die Spaltenzahl die Grundlage des Abgleichs ist, aber ohne sie können Sie nicht sagen, ob C₀ eine Last oder eine Länge ist. Leer, wenn die Tabelle keine Gruppierung hat.

Felder, die nur erscheinen, wenn sie zutreffen

Diese folgen derselben Regel wie unreadable: Ein false auf jeder Tabelle ist Rauschen, und wonach Sie suchen wollen, ist die Ausnahme.

FeldWann es erscheint
captionEin Zusatz, der zur ganzen Tabelle gehört (z. B. HG - 15, 20), geerbt von der Gruppe, unter der sie geliefert wurde.
kindWelche Art Tabelle es unserer Meinung nach ist. Auf jeder Tabelle vorhanden; der Wert ist ein kurzes Etikett, kein Versprechen.
layout_disputedDie Layout-Lesungen sind sich nicht einig, dass hier eine Tabelle ist. Wir liefern trotzdem, was wir extrahiert haben — aber prüfen Sie diese gegen die Originalseite, bevor Sie ihr vertrauen. Das ist eine andere Achse als die confidence auf Zellebene: Sie stellt in Frage, ob die Tabelle existiert, nicht, ob ein Wert richtig gelesen wurde.
ocr_unsupportedKeine unabhängige OCR-Lesung hat überlappenden Inhalt für diese Tabelle gefunden. Gleiches Prinzip wie oben: markiert, nicht verworfen.
span_gridDas Raster mit verbundenen Zellen hinter einer Tabelle, deren Zellen sich über Zeilen oder Spalten erstrecken. Die flachen rows, die Sie bekommen, sind dieses abgeflachte Raster; dies ist die ursprüngliche Form.
colbandsSpaltenbänder — ein Kopf, der mehrere Spalten unter einer Beschriftung zusammenfasst.
unfoldedDiese Tabelle wurde über eine Ausklappseite hinweg wieder zusammengesetzt.
sheetDer Name des Arbeitsblatts. Nur bei Tabellenkalkulations-Eingaben, die derzeit abgeschaltet sind — das Feld bleibt beschrieben, damit sich der Vertrag nicht ändert, wenn wir Tabellenkalkulationen wieder einschalten.
Bestellcodes sind ein Zusatz, kein Ersatz. Wenn eine Tabelle eine gestufte Bestellcode-Tabelle ist, liefern wir zusätzlich segments (jeder Teil des Codes: wie er heißt, welche Werte erlaubt sind) und einen example_code. Die Tabelle selbst wird unverändert geliefert — alles, was Sie bereits lesen, funktioniert weiter.

Jede Tabelle trägt außerdem bbox — den Rahmen der ganzen Tabelle auf der Seite in denselben PDF-Punkt-Koordinaten wie Zellen, Fließtext und Bilder (die Vereinigung ihrer Zellrahmen; fehlt, wenn keine ihrer Zellen einen hat) — und order, ihre Position in der Lesereihenfolge der Seite. Wenn die Layout-Lesung uneins ist, wie viele Tabellen eine Seite hat, wird order stattdessen aus bbox gemessen: Es entspricht dem order des letzten Fließtext- oder Bildblocks über der Tabelle. Zusammen mit pages[].width/height reicht das, um die Seite als strukturiertes Layout wieder aufzubauen.

Fließtext und Bilder

Das Ergebnis besteht nicht nur aus tables. Jedes Dokument trägt auch prose (den laufenden Text — Überschriften und Absätze) und images (ausgeschnittene Abbildungen). Beide werden genauso abgeglichen wie Zellen, und beide sagen, wer sie bestätigt hat.

prose

{"page": 7,
 "index": 2,
 "text": "Preload classes are selected according to the rail size.",
 "confidence": "verified",
 "sources": ["ocr-1", "ocr-2"],
 "bbox": [56.2, 98.6, 213.6, 236.9],
 "role": "paragraph",
 "level": 0,
 "order": 4}

Ein Eintrag pro Textblock, je Seite nummeriert. role ist heading oder paragraph; level ist die Überschriftentiefe (0 für Absätze); order ist die Position in der Lesereihenfolge der Seite, geteilt mit images, damit Sie sie verschränken können.

Die Lesung, die den Text wiedergibt, zählt nicht als eigener Zeuge. Ein Absatz ist verified, wenn eine andere Lesung der Seite denselben Inhalt enthält — die Quellen, die Sie sehen, sind also die, die zugestimmt haben, nie die, die geprüft wird. Absatzgrenzen müssen nicht übereinstimmen: Lesungen teilen Text unterschiedlich auf, und das ist ein Formatierungsunterschied, keine Abweichung.

Gemessen: 83–91% der Absätze kommen als verifiziert zurück über 7 Dokumente (2,812 Absätze). Die Streuung ist real und hängt vom Dokument ab — derselbe Vorbehalt wie bei bbox. Scans liegen am unteren Ende.

images

{"page": 7,
 "index": 1,
 "path": "images/p007_00.png",
 "confidence": "verified",
 "bbox": [56.2, 98.6, 213.6, 236.9],
 "order": 3,
 "also_on": [9],
 "sources": ["layout", "ocr", "pdf-image"]}

path ist relativ zum Ergebnispaket (dem zip-Export); also_on listet andere Seiten mit einer byteidentischen Kopie — Wiederholungen werden gemeldet, nicht entfernt, weil dieselbe Maßzeichnung berechtigterweise unter zwei Teilenummern erscheint.

Bilder verwenden ihr eigenes Quellenvokabular, weil die Frage lautet „ist hier eine Abbildung“, nicht „wurde dieser Wert richtig gelesen“. Beachten Sie, was ein Bild nicht verifiziert macht: pdf-image allein. Dass das PDF an dieser Stelle ein eingebettetes Bild enthält, sagt, dass die Datei ein Bild hat, nicht, dass wir das richtige eingerahmt haben — eine frühere Version hielt das für ausreichend, und drei Dokumente kamen zu 100% verifiziert zurück, während die Wahrscheinlichkeit, „eine Abbildung ganz verpasst“ zu haben, strukturell null war.

pages

[{"page": 6, "width": 612.0, "height": 792.0},
 {"page": 7, "width": 612.0, "height": 792.0, "unreadable": true}]

source_pages steht daneben, wenn Sie einen Seitenbereich angefordert haben: Es bildet die Position in der Lieferung auf die Seitenzahl in Ihrer Originaldatei ab, sodass ein Ergebnis immer auf die Seite verweisen kann, von der es stammt.

Ein Eintrag pro angeforderter Seite. width und height sind die Leinwandgröße in PDF-Punkten — ohne sie hat eine bbox keinen Rahmen, in dem sie sitzt.

unreadable: true bedeutet nicht „diese Seite hatte keine Tabellen“. Es bedeutet, dass wir die Seite gelesen haben und beide unabhängigen Lesungen fehlgeschlagen sind — nichts von dieser Seite ist in dieser Lieferung, und Sie sollten sich das Original ansehen. Eine Seite, auf der wirklich nichts steht, trägt gar keine Markierung.

Die Markierung erscheint nur auf Seiten, die fehlgeschlagen sind, danach zu suchen ist also günstig. Eine schlechte Seite reißt das Dokument nicht mehr mit: Die anderen Seiten werden normal geliefert. Schlägt jede Seite fehl, lehnen wir den Auftrag ab, statt Ihnen ein leeres Ergebnis zu übergeben.

Limits

LimitWertWarum diese Zahl
Dateigröße600 MBGemessen an echten gescannten Katalogen (121, 266, 443, 456 MB) — nicht geraten.
Seiten500 SeitenDer dickste Katalog, den wir gemessen haben, hat 235 Seiten, und ein Dokument mit 500 Seiten belegt die Warteschlange bereits rund zwei Stunden — darüber hinaus würde ein einzelner Auftrag alle dahinter aufhalten. Der kostenlose Test deckt 10 Seiten ab; selbst gehostete Installationen stellen PDFPAGES_MAX_PAGES ein.
FormatePDFDateiendungen zählen nicht — wir sehen auf den Inhalt. Bilder und Tabellenkalkulationen sind derzeit abgeschaltet — die Pipeline verarbeitet sie, aber sie kommen mit eigener Preisgestaltung zurück.
Parallelitätein Dokument auf einmalDie Pipeline lastet die CPU aus; die Warteschlange ist ein einzelner Worker. Weitere Einreichungen reihen sich ein — sie schlagen nicht fehl.
Neustartshöchstens 2-mal neu eingereihtDurch einen Dienstneustart unterbrochene Aufträge werden neu eingereiht (zwischengespeichert, der erneute Lauf kostet also fast nichts); darüber hinaus schlagen sie ehrlich fehl, statt endlos zu kreisen.
Aufbewahrung24 Stunden nach AbschlussWir behalten Ihre Daten nicht. Ergebnisse sind synchron verfügbar; holen Sie Ausschnitte innerhalb des Zeitfensters — danach wird der ganze Auftrag, OCR-Cache eingeschlossen, gelöscht. DELETE /v1/parse/{id} löscht früher. Der Kompromiss: Wird dasselbe Dokument später erneut gesendet, wird es als neuer Auftrag verarbeitet — und berechnet; keine Kopie überlebt, um das abzukürzen.
Setzen Sie einen User-Agent. Anfragen mit dem Standard-UA der Python-Standardbibliothek (Python-urllib/3.x) werden von den Bot-Regeln unseres CDN abgewiesen, bevor sie uns erreichen — Sie bekommen eine CDN-Fehlerseite, keinen der Fehler unten, es sieht also aus, als wäre der Dienst ausgefallen. requests, httpx und curl funktionieren wie sie sind; mit urllib setzen Sie einen beliebigen eigenen User-Agent.

Fehler

Immer {"detail": "…"}, für Menschen geschrieben — nie ein Serverpfad, nie ein Schlüsselname.

StatusWannHinweise
400Unbekanntes FormatDie Dateiendung zählt nicht — wir prüfen den Inhalt. Unterstützt: PDF.
401Unbekannter API-SchlüsselDer Schlüssel in Authorization / X-API-Key passt zu keinem Konto. Ein vertippter Schlüssel wird nie auf den anonymen Test herabgestuft; lassen Sie den Schlüssel weg, um ihn bewusst zu nutzen.
400Ein Format, das wir abgeschaltet habenWir nehmen vorübergehend nur PDF an. Bilder und Tabellenkalkulationen werden von der Pipeline unterstützt, sind aber abgeschaltet — sie kommen mit eigener Preisgestaltung zurück. Das ist ein anderer Fehler als der oben: Die Datei ist in Ordnung, wir nehmen sie nur gerade nicht an.
400Datei zu groß oder leerDas Limit beträgt 600 MB.
400pages unter 1Fordern Sie so viele Seiten an, wie Sie brauchen; der Server setzt die Obergrenze durch.
400Nicht unterstütztes ExportformatGET akzeptiert xlsx, csv, json und zip (das Ergebnispaket: dataset.json plus jedes ausgeschnittene Bild); POST /v1/export akzeptiert xlsx und csv.
413Body des zustandslosen Exports zu großPOST /v1/export akzeptiert Datensätze bis 600 MB.
402Unzureichendes GuthabenPrepaid-Tarife: Die Kosten dieses Dokuments (Seiten × Seitenpreis) übersteigen Ihr Guthaben — Aufträge laufen nur, wenn das Guthaben sie deckt. Die Antwort nennt Ihr verbleibendes Guthaben und was dieses Dokument braucht — laden Sie auf und senden Sie erneut; nichts wird eingereiht und nichts berechnet.
429Ratenlimit des anonymen TestsDer Test ohne Registrierung hat stündliche/tägliche Seitenlimits (Missbrauchsschutz, keine Preisgestaltung). Die Antwort trägt Retry-After; angemeldete Prepaid-Konten unterliegen ihm nicht.
404Extraktion nicht gefundenFalsche job_id, oder der Dienst wurde neu gestartet und dieser Auftrag nicht wiederhergestellt.
404format=zip, wenn nichts ausgeschnitten wurdeDas Paket besteht aus den ausgeschnittenen Bildern plus dataset.json; ein Dokument, aus dem wir keine Abbildungen ausgeschnitten haben (eine Tabellenkalkulation oder eine Seite mit reinem Text), hat kein Paket. Die anderen drei Formate funktionieren weiterhin — json trägt dieselben Daten. Wir geben lieber 404 zurück, als Ihnen ein Archiv zu übergeben, das wie ein Ergebnis aussieht und keines ist.
409Export vor Abschluss angefordertFragen Sie zuerst ab, bis status gleich done ist.
500Abgeschlossen, aber die Ergebnisdatei fehltDas ist ein Fehler auf unserer Seite. Wir tun nicht so, als liefe es noch, und lassen Sie endlos abfragen.

Was hier nicht ist

Nicht verfügbarWarum
POST /v1/webhooksAbschluss-Callbacks. Fragen Sie vorerst GET /v1/parse/{id} ab; bei 10 Seiten (≈600 s kalt) reicht Polling völlig aus.
page_rangeSie können nur die ersten N Seiten anfordern, nicht die Seiten 100–110. Für dicke Kataloge ist das eine echte Einschränkung: Ein 235-seitiger Katalog hat seine Spezifikationstabellen in der hinteren Hälfte, und pages zählt ab Seite 1.
GET /v1/jobs, POST /v1/cancel/{id}Auflisten und Abbrechen. Noch nicht gebraucht, also nicht gebaut. (Löschen gibt es: DELETE /v1/parse/{id}.)

Der ehrliche Teil

Scans verschlechtern das Ergebnis spürbar. Wir nutzen die Textebene des PDFs als zusätzliche unabhängige Lesung; ohne sie sinkt die Abgleichabdeckung in unseren Messungen auf 1/3 bis 1/18. text_layer wird in der 202-Antwort gemeldet — Sie müssen nicht auf das Ende des Laufs warten, um es zu erfahren.

Die Genauigkeit schwankt stark je Dokument. Wie wir messen, die Stichprobengröße und wo wir scheitern, ist dokumentiert, mit von Menschen geprüften Untergrenzen. Ein pauschales „99%+“ schreiben wir hier nicht hin.