How Ground Works
Both objects you send describe positions in the same Markdown string. A field’sranges say which characters the value was quoted from. A block’s grounding.range says which characters the block covers. Ground overlaps the two and returns every block a field’s ranges fall inside.
The join is stateless. Nothing is stored server-side, and the block ids in the response resolve only against the structure you send in the same request.
You send two objects you already have from earlier responses:
extraction_metadata: the per-field metadata returned by Extract, whose leaves are{value, ranges}objects.structure: the block tree returned by Parse, whose blocks each carry agroundingobject.
Pair the Extraction with Its Own Parse
Theextraction_metadata must come from an Extract call that ran on the markdown of the same Parse response the structure came from. Re-parsing invalidates an older extraction, because block ranges shift between parses even of the same file. If the locations come back wrong, see Troubleshoot Grounding.
Ground cannot detect a mismatched pair, so check it in code. The Extract response’s metadata.doc_id carries the job_id of the parse whose markdown it read:
Call the Ground API
Send both objects to the ground endpoint with a POST request. The endpoint accepts a JSON body (used by the libraries below) or multipart form data with each field JSON-serialized (used in the cURL example). The cURL example assumes you saved the Parse response toparse.json and the Extract response to extract.json.
For the full request and response contract, see the API reference.
The Grounding Tree
The response’sgrounding field mirrors your extraction_metadata tree: nested objects and arrays keep their shape, so a nested field like issuer.name resolves to grounding.issuer.name. Each {value, ranges} leaf is replaced by one of three values:
Matching Blocks
Only content blocks are returned. Thepage nodes in the structure never appear, because pages are containers rather than content. Each returned block reports its own page number in grounding.page instead.
A field with multiple ranges pools the blocks from all of them, without duplicates. A single range can still match more than one block: a value inside a table matches both the table and the table_cell that contains it, so you can highlight the whole table or just the cell.
Each entry in the list identifies one block from the structure you sent:
Matches Inside a Block
Thegrounding on a returned block covers the whole block. When the block also carries atomic_grounding, the response narrows the location to the individual entries the field’s ranges overlap, each with its own, tighter box.
Each entry is an {index, page, range, box} object, and carries a confidence score as well on a parse. The index is the entry’s position in the block’s own atomic_grounding array, so you can match it back to the block’s full list.
A returned block can also carry no entries at all:
Example Response
This response grounds three fields extracted from a one-page PDF parsed with . Thereport_number was quoted from a text block, so the returned block carries the matching line entry. The serial_number sits in a table, so its range matches both the table and the table_cell that contains it. The report has no purchase order, so purchase_order has no source passage and its grounding is null.
Metadata
Themetadata field provides information about the request:
Limits
- The Ground API is synchronous only. There is no Ground Jobs API, because the join completes quickly and the response arrives inline.
- There is no
modelparameter. The join is a deterministic overlap computation, so there is no model version to pin. - The Ground API is not available for organizations with Zero Data Retention enabled. Requests from ZDR-enabled organizations return a 501 error. See Troubleshoot Grounding.