curl --request POST \
--url https://ndi-api.nace.ai/v1/workspaces/{workspace_id}/tools/folder-metadata \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"category": "<string>",
"directory": "/",
"name_contains": "<string>",
"page_size": 100,
"recursive": false,
"start_after": "<string>"
}
'{
"categories": [
{
"count": 123,
"name": "<string>"
}
],
"coverage": {
"labels_required": [
"<string>"
],
"request_access_hint": "<string>",
"restricted_candidates": 0
},
"directory": "<string>",
"file_entries": [
{
"ingestion_status": "discovered",
"path": "<string>",
"size_bytes": 123,
"category": "<string>",
"kind": "<string>",
"uploaded_at": "2023-11-07T05:31:56Z"
}
],
"files_truncated": true,
"ingestion_summary": {},
"overall_files": 123,
"subdirectories": [
{
"name": "<string>",
"overall_files": 123,
"failed_files": 123,
"top_categories": [
{
"count": 123,
"name": "<string>"
}
]
}
],
"hint": "<string>",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}folder_metadata
List one folder of the workspace: file counts, categories, subfolders, and the files’ exact paths.
Cost class: fast.
Explore in steps instead of listing everything at once:
- Call with the defaults on
/(the workspace root): the folder’s own files plus one summary per subfolder (file count, top categories, failed-ingestion count). - Descend with
directory=<folder>, or narrow withname_contains=(find a file by part of its name),category=,ingestion_status=(e.g.failed) orkind=. Counts and listing narrow together, and a narrow covers the whole subtree unlessrecursive=falseis sent. - Pass a
file_entries[].pathtofile-metadatato see what is inside that file, then ask withqa-fileorquery-tables.
Every path is relative to the workspace root and never includes the
workspace id. name_contains finds files by what they are called — files
whose ingestion failed included; the search tools find them by what they
contain.
A directory that names a file is refused with invalid_request
pointing at file-metadata. An unfiltered call that matches nothing
answers with a hint naming the nearest existing folder and what it
holds, so a mistyped folder is not a dead end.
file_entries comes one page_size page at a time, sorted by path;
files_truncated reports a cut — resume with start_after=<last path>
or narrow. Counts and listing only include files the caller’s access
labels allow; coverage says how many were withheld.
curl --request POST \
--url https://ndi-api.nace.ai/v1/workspaces/{workspace_id}/tools/folder-metadata \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"category": "<string>",
"directory": "/",
"name_contains": "<string>",
"page_size": 100,
"recursive": false,
"start_after": "<string>"
}
'{
"categories": [
{
"count": 123,
"name": "<string>"
}
],
"coverage": {
"labels_required": [
"<string>"
],
"request_access_hint": "<string>",
"restricted_candidates": 0
},
"directory": "<string>",
"file_entries": [
{
"ingestion_status": "discovered",
"path": "<string>",
"size_bytes": 123,
"category": "<string>",
"kind": "<string>",
"uploaded_at": "2023-11-07T05:31:56Z"
}
],
"files_truncated": true,
"ingestion_summary": {},
"overall_files": 123,
"subdirectories": [
{
"name": "<string>",
"overall_files": 123,
"failed_files": 123,
"top_categories": [
{
"count": 123,
"name": "<string>"
}
]
}
],
"hint": "<string>",
"job_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}{
"error": {
"code": "invalid_request",
"detail": null,
"message": "Request body has extra fields that this operation does not accept.",
"request_id": "req-01j9k2n3p4q5r6s7t8v9",
"retryable": false
}
}Authorizations
Headers
Replaying a request with the same key returns the original job with 200, never a second job. The key is kept with the job for replay and never cleared, so it must not contain personal data.
200Path Parameters
Workspace identifier.
Body
Request body for folder-metadata: describe one folder of the workspace.
Non-recursive by default: the first call on a folder orients (its own files plus a summary per subfolder), and the caller descends or narrows from there instead of receiving the whole subtree at once.
A narrow (category, ingestion_status, kind, name_contains)
implies recursion unless recursive is sent explicitly: the counts
those names come from cover subtrees, so the follow-up call must scope the
same subtree. An explicit recursive=false alongside a narrow is honored.
Only files whose category exactly matches this name, as a previous response listed it.
Folder to describe, relative to the workspace root: / (the default) is the root, evidence/2025 a folder under it. Never prefix it with the workspace id.
1024Only files in this ingestion status — e.g. failed to list what did not ingest.
discovered, queued, ingesting, ingested, stale, expired, failed, not_required Only files of this kind: document (paged or prose), table, or media.
document, table, media, json Only files whose path contains this text, case-insensitively — how to find a file you know by name. % and _ match literally.
1 - 256File entries per page. The counts always cover the whole scope.
1 <= x <= 500Describe the folder's whole subtree instead of its own files only. A narrow implies true unless sent.
Resume the file listing strictly after this path: the last file_entries path of the previous page.
1024Response
Successful Response
Response body for folder-metadata.
Counts are filtered by both the caller's access predicate and the requested
directory — the two compose as an intersection, so the view is neither
wider than the access gate nor wider than the declared scope.
file_entries lists the visible source files the counts cover (same
scope and recursion as the counts), path-sorted, one page at a time
(page_size); files_truncated reports a cut page — resume with
start_after=<last path>, or narrow. Source paths only, never ingestion
derivatives.
File counts per category across the scope.
Show child attributes
Show child attributes
What the access gate withheld from these counts, as counts and label names only.
Show child attributes
Show child attributes
The folder described, relative to the workspace root (/ is the root).
Files in scope, sorted by path, one page at a time.
Show child attributes
Show child attributes
True when file_entries is one page of a longer listing; resume with start_after.
File counts per ingestion status across the scope.
Show child attributes
Show child attributes
Files in scope that the caller can see: the folder, or its subtree when recursive.
The folder's immediate subfolders, each summarizing its subtree.
Show child attributes
Show child attributes
Present only when an unfiltered call matched nothing: the nearest existing folder and what it holds.
The external operation job; absent for commands inside a search job.