optii by chut.app

Eén endpoint.
Eén header.
Eén bestand.

Alles hieronder is geverifieerd tegen de draaiende API. Basis-URL https://api.optii.eu

Authenticatie

Stuur uw sleutel in de X-API-Key-header. Sleutels beginnen met optii_sk_ en worden één keer getoond, bij het aanmaken. Sleutels worden gehasht opgeslagen; een verloren sleutel wordt geroteerd, niet hersteld.

Elk antwoord draagt een X-Request-ID-header. Vermeld die wanneer u ons schrijft.

curl https://api.optii.eu/ocr/extract \
  -H "X-API-Key: optii_sk_…" \
  -F "file=@document.pdf"

POST/ocr/extract

Multipart-upload van één bestand. Geeft elke regel terug met zijn bounding box en betrouwbaarheid, in leesvolgorde, pagina na pagina.

Queryparameters

structured
false (standaard) voor regels, true voor Belgische documentvelden (volgende sectie).
format
v2 (standaard). legacy geeft de platte factuurvorm van de klanten van 2025 terug; gebruik het niet voor nieuwe code.

Antwoord 200

{
  "success": true,
  "text": "DUMONT & FILS SPRL\nRue de la Loi 42 · 1000 Bruxelles\nTVA BE0202239951\n…",
  "lines": [
    { "text": "DUMONT & FILS SPRL", "confidence": 0.996, "bbox": [[50.0, 50.0], [304.0, 50.0], [304.0, 84.0], [50.0, 84.0]] },
    { "text": "Rue de la Loi 42 · 1000 Bruxelles", "confidence": 0.991, "bbox": [[56.0, 82.0], [286.0, 82.0], [286.0, 100.0], [56.0, 100.0]] },
    { "text": "TVA BE0202239951", "confidence": 0.993, "bbox": [[56.0, 106.0], [198.0, 106.0], [198.0, 124.0], [56.0, 124.0]] }
  ],
  "confidence": 0.991,
  "source": "ocr",
  "quality": { "blur": 812.4, "long_side_px": 2339, "low_confidence_ratio": 0.0, "warnings": [] },
  "file_hash": "a3b2c1d4e5f6",
  "processing_time_ms": 342
}

Velden

text
de volledige tekst, regels gescheiden door regeleinden
lines[]
één object per regel: text, confidence (0 tot 1), bbox als vier hoekpunten [[x, y], …] in paginapixels, met de klok mee vanaf linksboven
confidence
gemiddelde regelbetrouwbaarheid
source
text, ocr of hybrid, zie Bron en kwaliteit
quality
blur, long_side_px, low_confidence_ratio, warnings[]
file_hash
SHA-256 van het bestand, eerste tekens; hetzelfde bestand geeft altijd dezelfde waarde
processing_time_ms
servertijd in milliseconden, upload niet meegerekend

POST/ocr/extract?structured=true

Dezelfde oproep met ?structured=true. De motor herkent het documenttype uit de tekst (invoice, credit_note, debit_note, receipt, anders unknown), extraheert de Belgische velden en voert de controles uit. Als de classifier zeker is, draagt document_type zijn label in de plaats.

Een veld dat niet op de pagina staat, is null. Bedragen zijn getallen met een punt, datums blijven zoals gedrukt (dd/mm/yyyy op het meeste Belgische papier).

{
  "document_type": "invoice",
  "source": "ocr",
  "quality": { "blur": 812.4, "long_side_px": 2339, "low_confidence_ratio": 0.0, "warnings": [] },
  "supplier_name": "DUMONT & FILS SPRL",
  "supplier_vat": "BE0202239951",
  "supplier_iban": "BE68539007547034",
  "document_number": "2024-0847",
  "document_date": "15/03/2024",
  "due_date": "14/04/2024",
  "structured_communication": "+++123/4567/89002+++",
  "currency": "EUR",
  "line_items": [
    { "description": "Conseil juridique — mars 2024", "quantity": 10, "unit_price": 125.0, "line_total": 1250.0, "vat_rate": 21.0 }
  ],
  "vat_subtotals": [ { "rate": 21.0, "base_amount": 1250.0, "vat_amount": 262.5 } ],
  "total_excl_vat": 1250.0,
  "total_vat": 262.5,
  "total_incl_vat": 1512.5,
  "validations": [
    { "check": "vat_checkdigit", "passed": true, "message": "" },
    { "check": "iban_mod97", "passed": true, "message": "" },
    { "check": "structured_comm_mod97", "passed": true, "message": "" },
    { "check": "totals_sum", "passed": true, "message": "" }
  ],
  "confidence": 0.91,
  "processing_time_ms": 342
}

Controles

vat_checkdigit
de controlecijfers van het Belgische btw-nummer (97 min de eerste acht cijfers mod 97)
iban_mod97
de IBAN herschikt mod 97 is gelijk aan 1
structured_comm_mod97
de controlecijfers van de gestructureerde mededeling +++xxx/xxxx/xxxxx+++
totals_sum · vat_subtotals_sum · vat_bases_sum
total_excl_vat + total_vat = total_incl_vat op één cent na
line_items_sum
de lijnen tellen op tot het totaal excl. btw wanneer aanwezig

POST/ocr/classify

Multipart-upload van één bestand. De tekst wordt gelezen (tekstlaag of OCR) en door een XLM-RoBERTa-model geclassificeerd in een van 32 Belgische documenttypes.

Queryparameters

top_k
aantal voorspellingen dat terugkomt, 1 tot 20, standaard 5.

Antwoord 200

{
  "success": true,
  "document_type": "acc_purchase_invoice",
  "confidence": 0.9361,
  "confident": true,
  "predictions": [
    { "label": "acc_purchase_invoice", "confidence": 0.9361, "rank": 1 },
    { "label": "acc_sales_invoice", "confidence": 0.0298, "rank": 2 },
    { "label": "acc_credit_note", "confidence": 0.0112, "rank": 3 }
  ],
  "processing_time_ms": 388
}
document_type
het label als confident true is, anders unknown
confident
true als de hoogste kans op of boven de drempel ligt en het label geen fallback is
predictions[]
label, confidence, rank, beste eerst

Labels zijn snake_case met een familieprefix, bijvoorbeeld acc_purchase_invoice of acc_sales_invoice. De volledige lijst staat op het dashboard.

Bron en kwaliteit

Elk extract-antwoord zegt waar de tekst vandaan komt.

text
de PDF had een bruikbare tekstlaag; de tekens zijn exact, elke regel heeft confidence 1
ocr
elke pagina ging door de motor
hybrid
sommige pagina’s hadden een laag, andere niet

quality quality wordt berekend op de pagina’s die door OCR gingen:

blur
variantie van de Laplaciaan op een grijswaardenbeeld verkleind tot 1500 px; lager is waziger
long_side_px
de kleinste lange zijde van een pagina in pixels
low_confidence_ratio
aandeel regels onder 0.80 betrouwbaarheid
warnings[]
een of meer van low_resolution (onder 1500 px), blurry (onder 400), low_confidence (ratio boven 0.15)

Als warnings niet leeg is, toon de gebruiker de pagina en vraag een nieuwe scan. De cijfers kunnen nog kloppen; u kunt het niet weten.

Idempotentie

Stuur een Idempotency-Key-header (elke string tot 255 tekens, een UUID is prima). Gedurende 24 uur geeft dezelfde sleutel met hetzelfde bestand en dezelfde parameters het opgeslagen antwoord terug, zonder tweede lezing en zonder tweede telling. Dezelfde sleutel met een ander bestand antwoordt 409 idempotency_conflict.

De vingerafdruk is de SHA-256 van het bestand plus de parameters, dus een herhaalde multipart-upload matcht ook als de boundary verschilt.

Rate limits en quota

Limieten gelden per plan en per sleutel. De tabel is de live configuratie.

PlanVerzoeken / minMax. bestandSleutelsMaandquotum
Free105 MB1500
Pro6020 MB510.000
Enterprise30020 MB100onbeperkt

Boven de rate limit: 429 rate_limited met Retry-After. Boven het quotum: 429 met een bericht dat het quotum noemt. Het publieke demo-endpoint laat 10 verzoeken per minuut per IP toe en 5 MB.

Fouten

Elke fout is JSON met twee velden: error, een snake_case-code, en message, een zin voor mensen. Parse het bericht nooit.

HTTP/1.1 413 Payload Too Large
X-Request-ID: 6f1c0a2b9d3e
Content-Type: application/json

{ "error": "file_too_large", "message": "File too large (max 5MB)" }
StatuserrorWanneerWat te doen
400unsupported_file_typeextensie niet in pdf png jpg jpeg tiff tif bmp webpconverteer het bestand
401unauthorizedontbrekende of onbekende sleutelcontroleer de sleutel in het dashboard
403forbiddenhet plan laat het niet toe (sleutellimiet, grootte)zie prijzen
409idempotency_conflictzelfde Idempotency-Key, ander bestandgebruik een nieuwe sleutel
413file_too_largeboven het max. bestand van het plancomprimeer of splits
422validation_failedgeen file-veld, slechte queryparameterlees de sectie over het verzoek
429rate_limitedrate limit of maandquotumwacht op Retry-After, of upgrade
500processing_failedde motor kon het bestand niet lezenprobeer één keer opnieuw, schrijf ons dan met de request id
503model_unavailablede motor laadt na een herstartprobeer over enkele seconden opnieuw
503db_unavailablegebruiksdatabase down; lezen werkt nogprobeer opnieuw

Formaten en limieten

Invoer: PDF (tekst of gescand, meerdere pagina’s), PNG, JPG, TIFF, BMP, WebP. Max. 20 MB met een sleutel, 5 MB op de demo. Gelezen talen: Frans, Nederlands, Duits, Engels; de motor kan 50 schriften aan, maar de veldextractie en de classifier zijn Belgisch.

Uitvoer: JSON, UTF-8. De regelvolgorde is de leesvolgorde per pagina. Kaders zijn veelhoeken in de pixelruimte van de gerenderde pagina.

Snippets

Geen SDK te installeren. Drie snippets die werken zoals ze zijn.

curl -X POST "https://api.optii.eu/ocr/extract?structured=true" \
  -H "X-API-Key: optii_sk_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@facture-2024-0847.pdf"

OpenAPI

Het machineleesbare contract staat op https://api.optii.eu/openapi.json. Het is het gecureerde toolmanifest dat het chut.app-platform gebruikt; de dashboardroutes staan er niet in.

Changelog

Bekijk de changelog →