> ## 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.

# Upload a file

> POST /upload — stage a document once, reference it in any job

Stages a document and returns an opaque `file_id`. Reference it in any job body as `source_url: "ndi://file/<file_id>"` — upload once, then parse, categorize, and ground the same file without re-sending the bytes.

```text theme={"dark"}
POST /upload
Content-Type: multipart/form-data
```

## Request

<ParamField body="file" type="file" required>
  The document, as a `multipart/form-data` part named `file`. The filename you
  send is captured and used for format detection. Maximum size **200 MB**
  (`413` when exceeded).
</ParamField>

## Response

<ResponseField name="file_id" type="uuid">
  Opaque handle. Use it as `ndi://file/<file_id>` in any `source_url`.
</ResponseField>

<ResponseField name="file_name" type="string">
  The captured filename. Jobs started from this handle inherit it, so you can
  omit `file_name` in job bodies.
</ResponseField>

<ResponseField name="expires_at" type="datetime">
  When the handle stops working (\~6 days after upload). A job started with an
  expired handle fails with `410 Gone` — just upload the file again.
</ResponseField>

## Notes

* Handles are tenant-scoped: another tenant's `file_id` returns `404`, never your data.
* Uploads are **not** deduplicated and take no `idempotency_key` — uploading the same file twice just yields two handles, which is harmless. Idempotency matters for *jobs*, not uploads.
* Uploading does not start any processing and does not count against your concurrent-jobs limit (it does count toward requests-per-minute).

## Example

```bash theme={"dark"}
curl -s "$NDI_BASE/upload" \
  -H "X-API-Key: $NDI_API_KEY" \
  -F "file=@./annual-report.pdf"
```

```json theme={"dark"}
{
  "file_id": "7f4d2a10-3b7e-4c25-9f61-8f0f4f0a1b2c",
  "file_name": "annual-report.pdf",
  "expires_at": "2026-07-18T21:04:11Z"
}
```

Then start a job with it:

```bash theme={"dark"}
curl -s "$NDI_BASE/parse" \
  -H "X-API-Key: $NDI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "file": { "source_url": "ndi://file/7f4d2a10-3b7e-4c25-9f61-8f0f4f0a1b2c" } }'
```
