> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ndi.nace.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Granular vs workspace workflows

> Two ways to use NDI — single-operation or persistent

NDI supports two integration patterns. They can coexist, and you can adopt
workspaces later without breaking granular operations.

***

## Granular operations

**No workspace.** Parse, classify, extract, or ground individual documents and
get back results immediately.

* Provide a document via `POST /v1/uploads`, a public URL, or a workspace file reference.
* Call an operation: `POST /v1/parse`
* Get results: markdown, categories, extracted JSON, or target locations.
* Results include presigned URLs that expire when the job's `payload_expires_at` passes.

**Use granular when:**

* You want single-document intelligence without long-term storage.
* You're analyzing a one-off PDF or spreadsheet.
* You're integrating document intelligence into an existing pipeline.

**Example:**

```bash theme={"dark"}
curl -X POST "$NDI_BASE_URL/v1/parse" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source": {"type": "url", "url": "https://example.com/report.pdf", "file_name": "report.pdf"}}'
```

***

## Workspace workflows

**Persistent storage + derived outputs + querying.** Upload files into a workspace,
trigger ingestion to build derivatives (parsed markdown, extracted tables, search
indexes), then query the corpus.

* Create a workspace with a chosen domain and access labels.
* Upload files: `POST /v1/workspaces/{workspace_id}/files`
* Ingest files to create derivatives: `POST /v1/workspaces/{workspace_id}/ingestions`
* Query with tools: search, file reading and QA, knowledge graph walk, intelligent search.

**Use workspaces when:**

* You maintain a corpus of documents (engagement files, reference materials).
* You need to search or query across many files.
* You want to build a knowledge graph of relationships.
* You need to track file history and versions.

**Example:**

```bash theme={"dark"}
# Create workspace (domain_slug identifies the taxonomy vocabulary)
WS=$(curl -s -X POST "$NDI_BASE_URL/v1/workspaces" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "q4-audit", "domain_slug": "generic"}' | jq -r '.workspace_id')

# Upload a file
FILE=$(curl -s -X POST "$NDI_BASE_URL/v1/workspaces/$WS/files" \
  -H "X-API-Key: $NDI_API_KEY" \
  -F "file=@document.pdf" \
  -F 'metadata={"path":"document.pdf"}' | jq -r '.result.file.file_id')

# Wait for upload job to finish, then ingest
JOB=$(curl -s -X POST "$NDI_BASE_URL/v1/workspaces/$WS/ingestions" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"selection\":{\"type\":\"file_ids\",\"file_ids\":[\"$FILE\"]}}" | jq -r '.job_id')

# Poll until ingestion done, then query
curl -X POST "$NDI_BASE_URL/v1/workspaces/$WS/tools/hybrid-search" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "revenue by segment"}'
```

***

## Key differences

| Aspect                | Granular                          | Workspace                    |
| --------------------- | --------------------------------- | ---------------------------- |
| **Storage**           | None (results are presigned URLs) | Persistent                   |
| **Discovery**         | Single operation                  | Corpus query tools           |
| **Derivatives**       | On-demand                         | Built by ingestion           |
| **Onboarding**        | None                              | Choose domain, access labels |
| **Source addressing** | URL, upload, or workspace file    | File uploaded to workspace   |
| **Cost**              | Per operation                     | Per file ingested            |

***

## Shared concepts

Both patterns share:

* **Authentication** — `X-API-Key` header
* **Job lifecycle** — POST returns 200/202, poll with `GET /v1/jobs/{job_id}`
* **Idempotency** — `Idempotency-Key` header for replay safety
* **Errors** — typed error codes and messages

See [Jobs and idempotency](/concepts/jobs-idempotency) for details on async semantics.
