Ground answers “where does this value appear in the source document?” You submit one or more items — literal strings or semantic descriptions — and get back, per item, the locations where it was found: normalized bounding boxes on pages, cell ranges in spreadsheets, character ranges in text files, or line indices in JSONL.
Typical uses: drawing citation highlights over a PDF viewer, verifying that an extracted figure really exists in the source, and linking derived data back to its provenance.
Endpoint Behavior POST /groundStarts the job and waits for the result (bounded by timeout_seconds). POST /ground_asyncStarts the job and returns 202 {"job_id": …} immediately.
Request
Sync endpoint only. Max seconds to wait, between 1 and 300.
The document to search. Same shape as everywhere else — source_url
(+ file_name for s3:///https://). See Files & sources .
Values to locate — between 1 and 30 per request. Each item is matched
independently; split larger batches across requests. Your identifier for this item, echoed back in the result so you can
correlate.
The text, value, or phrase to locate. Closest match wins.
When true, query is a description of what to find (e.g.
"total liabilities" should match the line item even if the document
words it differently). When false, matching is literal.
Optional hints that narrow the search and improve precision. Text expected near the target — disambiguates repeated values.
1-based page numbers to prioritize.
Sheet expected to contain the value.
Range hint, e.g. "B12:D18".
Minimum confidence (0–1) for a match to be included.
When true, visual matches also include a cropped_image_url — an
image of the matched region, useful for human review UIs.
Artifacts from prior NDI runs on the same file that speed up and improve
grounding. All URLs must be s3:// URLs previously returned by NDI. markdown_url from a prior parse of this file.
Transcript derived from the source media.
JSONL artifact derived from the source.
Supported extensions: everything parse supports except .eml .msg .vsd .vsdx, plus .bmp .jsonl .md .mdx.
Result
Discriminator — always "ground".
One entry per requested item, in no guaranteed order — correlate by
item_id. Whether any match cleared the confidence threshold.
Locations, tagged by match_type (see match types below).
Items with at least one match.
Match types
Every match carries confidence (0–1) and usually matched_text (the text found at the location). The location fields depend on match_type:
match_typeLocation fields Produced for visual_regionpage (1-indexed), x, y, w, h — a bounding box normalized to the page (0–1) , origin top-left; optional cropped_image_urlPDFs, images, rendered documents spreadsheet_rangesheet_name, cell_range (e.g. "B12:D14")Spreadsheets text_rangestart_char, end_char — offsets into the textPlain-text sources jsonl_recordline_index, keysJSONL sources audio_rangestart_ms, end_msMedia transcripts
To draw a highlight from a visual_region at render size W×H pixels:
left = x*W, top = y*H, width = w*W, height = h*H.
Examples
Semantic + hints
Spreadsheet
curl -s " $NDI_BASE /ground" \
-H "X-API-Key: $NDI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"file": { "source_url": "ndi://file/7f4d2a10-3b7e-4c25-9f61-8f0f4f0a1b2c" },
"items": [
{
"item_id": "liab-total",
"query": "total liabilities",
"semantic": true,
"hints": { "visual": { "anchor_text": "Balance Sheet", "page_hints": [41, 42, 43] } }
},
{
"item_id": "auditor",
"query": "Independent Auditor' \' 's Report",
"semantic": false
}
],
"options": { "confidence_threshold": 0.8, "return_cropped_images": true },
"idempotency_key": "ground-annual-report-v1"
}'
curl -s " $NDI_BASE /ground" \
-H "X-API-Key: $NDI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"file": {
"source_url": "https://example.com/trial-balance.xlsx",
"file_name": "trial-balance.xlsx"
},
"items": [
{
"item_id": "cash-eoy",
"query": "1,204,331.00",
"hints": { "spreadsheet": { "sheet_name": "TB Dec 2025" } }
}
]
}'
{
"job_id" : "b1e6d5c4-2a3f-4e89-a0b1-c2d3e4f5a6b7" ,
"action" : "ground" ,
"status" : "succeeded" ,
"result" : {
"result_type" : "ground" ,
"results" : [
{
"item_id" : "liab-total" ,
"found" : true ,
"matches" : [
{
"match_type" : "visual_region" ,
"page" : 42 ,
"x" : 0.118 , "y" : 0.552 , "w" : 0.312 , "h" : 0.021 ,
"confidence" : 0.93 ,
"matched_text" : "Total liabilities $1,204,331" ,
"cropped_image_url" : "https://…(time-limited)…/crop-0.png"
}
],
"error" : null
},
{
"item_id" : "auditor" ,
"found" : false ,
"matches" : [],
"error" : null
}
],
"total_items_found" : 1 ,
"total_items_requested" : 2 ,
"duration_ms" : 8412
},
"error" : null ,
"created_at" : "2026-07-12T21:15:40Z" ,
"started_at" : "2026-07-12T21:15:41Z" ,
"completed_at" : "2026-07-12T21:15:49Z"
}