# Download an export artifact

`GET /v1/exports/{export_id}/download`

Streams the CSV artifact for a `COMPLETED` export. Uses the same
Bearer token as every other endpoint — no presigned URL, no embedded
credentials. The path itself is what `download_url` on
[Retrieve an export](/api/exports/getExport) points at.

Response shape:
- `Content-Type: text/csv`
- `Content-Disposition: attachment; filename="<subject>-<timestamp>.csv"`
- Body is the raw CSV (header row + data rows, UTF-8, `\n` line
  separator)

Returns `404` with a typed `error_code` for every error state — cross-org
access is intentionally indistinguishable from a missing or expired
export so foreign `export_id`s never leak existence:
- `EXPORT_NOT_FOUND` — does not exist in the caller's org
- `EXPORT_NOT_READY` — exists but `status` is still `PENDING` or `PROCESSING`
- `EXPORT_EXPIRED` — artifact has been purged past its 7-day retention

## Responses

### 200 — CSV artifact stream.

**text/csv**

- **string**

### 401 — Missing or invalid Bearer token

### 404 — Export not found, not ready, or artifact expired. See `error_code`
in the body for which.


**application/json**

- **object** — Standardized error format for all `/v1/*` endpoints. `error_code` is a
stable SCREAMING_SNAKE_CASE identifier clients can switch on.

  - `detail` (string) — Human-readable error message
  - `status_code` (integer) — HTTP status code
  - `error_code` (string) — Stable machine-readable error code
  - `request_id` (any) — Request identifier for correlation
  - `extra` (any) — Endpoint-specific additional context. For example,
IMAGE_DOWNLOAD_FAILED populates extra.failed_urls with per-URL
failure reasons so clients can triage bulk submissions.

  - `timestamp` (string)
