Extract
POST /v1/extract reads a GAEB DA XML file (the German
Leistungsverzeichnis exchange format, .x81 to .x86) and returns its
bill-of-quantities structure as a faithful, nested tree. It makes no decisions
for you: the hierarchy, every text element and every quantity come back exactly
as the file carries them. Composing that structure into embed-ready text is the
job of Chunk, where you control the knobs.
Request
Section titled “Request”Multipart upload, one file per request, up to 20 MB:
curl https://api.flinq.ai/v1/extract \ -H "Authorization: Bearer flq_your_key_here" \ -F "file=@LV_Rohbau.x83"import requests
with open("LV_Rohbau.x83", "rb") as f: r = requests.post( "https://api.flinq.ai/v1/extract", headers={"Authorization": "Bearer flq_your_key_here"}, files={"file": f}, )tree = r.json()["tree"] # nested group/item/remark nodesimport { readFile } from 'node:fs/promises';
const form = new FormData();form.append('file', new Blob([await readFile('LV_Rohbau.x83')]), 'LV_Rohbau.x83');
const r = await fetch('https://api.flinq.ai/v1/extract', { method: 'POST', headers: { Authorization: 'Bearer flq_your_key_here' }, body: form,});const { tree } = await r.json(); // nested group/item/remark nodesResponse
Section titled “Response”{ "object": "extract", "format": "gaeb", "project": { "name": "Neubau Testhalle", "label": "TH-01", "currency": "EUR", "date": "2026-03-01", "owner_name": "Stadt Musterstadt", "owner_city": "Musterstadt", "boq_name": "LV Rohbau", "boq_label": "Leistungsverzeichnis Rohbau" }, "tree": [ { "type": "group", "rno": "01", "label": "Rohbau", "description": "Rohbauarbeiten Alle Rohbauarbeiten gemäß VOB/C.", "children": [ { "type": "item", "rno": "01.02.0010", "short_text": "Ortbeton C25/30", "long_text": "Ortbeton der Festigkeitsklasse C25/30, Expositionsklasse XC2.", "additional_texts": ["Einbau lagenweise, verdichtet mit Innenruettler."], "qty": 12.5, "unit": "m2", "lump_sum": false, "unit_price": null, "total_price": null }, { "type": "remark", "text": "Hinweis: Ausschreibung nach VOB/A." } ] } ], "warnings": [], "usage": { "prompt_tokens": 1234, "total_tokens": 1234 }}The tree
Section titled “The tree”Four node types cover everything a GAEB file contains:
| Type | What it is |
|---|---|
group | A category (Gliederungsebene) with its own label, optional description and nested children. |
item | A position: short_text, long_text, additional_texts (sub-descriptions, in document order), qty, unit, lump_sum, and prices. |
remark | A Vorbemerkung: position-less prose between categories or items. |
unparsed | Content the parser did not recognize, preserved as raw text. Always paired with a warning. |
rno is the hierarchical position number: a position 0010 inside category
02 inside category 01 comes back as 01.02.0010.
Prices are preserved when present. Tender files (X83) carry no prices, so
unit_price and total_price are null. Bid and award files (X84, X85) carry
them, and the tree keeps them.
Tolerant parsing
Section titled “Tolerant parsing”The parser recognizes GAEB DA XML 3.2 and 3.3 automatically and does not
require an ideal file. Whatever it cannot map to a known node is preserved as
unparsed raw text with an entry in warnings, and an unparseable quantity
becomes qty: null with a warning rather than a silent zero. A request fails
with 422 in only two cases: the file is not well-formed XML, or its root
element is not <GAEB>.
Billing
Section titled “Billing”Billed flat per document: one parsed file costs EUR 0.02, whatever its
size (see Pricing). The usage object still reports the
token count of the extracted text (all labels, descriptions, position texts
and remarks); treat it as a planning figure for the downstream
chunk and embed calls, not as what this request
billed.