# Download a shared package

```http
GET /api/public/v1/contributor-network/items/{itemId}/download
```

**Scope**: `contributor-network.read`.

Downloads the exact immutable representation stored for one active, visible `lean-kernel-package` Contributor Network item. Use the `downloadUrl`, `packageFilename`, `packageSizeBytes`, and `packageSha256` returned by [List shared packages](./list-contributor-packages.md) or [Get a shared package](./get-contributor-package.md).

This operation returns file bytes directly, not the standard JSON success envelope. It never rebuilds a package from the author's current private Solution.

## Path parameter

| Parameter | Type, requirement, and meaning |
| :--- | :--- |
| `itemId` | **Required string.** Stable opaque Contributor Network item ID. Pass it through unchanged. |

This operation accepts no query parameters. An item that belongs to another Contributor Network kind is not downloadable through this Lean Kernel package operation.

## Package contents

- A package containing only `Submission.lean` is returned as the exact UTF-8 source bytes with `Content-Type: text/plain; charset=utf-8`.
- A package with auxiliary files is returned as an `application/zip` archive whose root mirrors the complete canonical Workspace path tree, including `Submission.lean` and files below `Submission/`.
- The response contains no official dependencies, build artifacts, compiled output, caches, logs, development inputs, evaluation results, server paths, credentials, or runtime configuration.

The downloaded representation must match the `workspaceFiles` shown by [Get a shared package](./get-contributor-package.md). The service validates the stored package bytes, file tree, manifest, Workspace digest, file count, and byte counts before returning any content.

## Example request

```bash
export SAIR_API_ORIGIN="https://api.sair.foundation"
export SAIR_DOWNLOAD_URL="/api/public/v1/contributor-network/items/cn_8fc20f8a7a3c4bd99506b5d51a6c905e/download"

curl -OJ \
  "$SAIR_API_ORIGIN$SAIR_DOWNLOAD_URL" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

`downloadUrl` is API-origin-relative. `-OJ` saves the attachment using the server-provided filename. Automated clients should pass through the URL unchanged, use `Content-Type` to select a decoder, and treat the filename only as display and save metadata.

## Successful response

For the two-file example used by the list and detail pages:

```http
HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="baseline.zip"
Content-Length: 432
```

For a single-file package, `Content-Type` is `text/plain; charset=utf-8` and `packageFilename` ends in `.lean`.

| Header | Meaning |
| :--- | :--- |
| `Content-Type` | `text/plain; charset=utf-8` for an exact single `Submission.lean`; `application/zip` for a complete multi-file Workspace. There is no content negotiation. |
| `Content-Disposition` | Supplies the safe server-selected `packageFilename`. Treat it as display metadata; do not parse a private Solution ID, Problem, author, or revision from it. |
| `Content-Length` | Exact response-body byte length. It equals `packageSizeBytes`; the example response contains exactly 432 bytes. |

Do not decode an `application/zip` response as text or save root-file text under a `.zip` filename. A ZIP-aware client must preserve every validated relative path and reject extraction outside its chosen destination directory.

## Verify the package

Compute SHA-256 over the exact downloaded response body and compare the lowercase hexadecimal digest with `packageSha256`:

```bash
shasum -a 256 "baseline.zip"
```

Also verify that the body length equals `packageSizeBytes`. `workspaceSha256` identifies the logical canonical Workspace manifest, not the download bytes, and must not be used as the file checksum.

For a ZIP, each extracted file's path, UTF-8 byte length, and SHA-256 digest must match the ordered `workspaceFiles` returned by the detail endpoint. A single-file response must match its sole `Submission.lean` entry exactly.

## Visibility and retries

Only an active, visible Lean Kernel package is downloadable. Missing, withdrawn, hidden, force-revoked, and other-kind items all return the same `404 NOT_FOUND`, so the operation does not disclose whether a supplied ID exists in another state or kind.

Retry `503` with bounded backoff. A `500 ARTIFACT_CORRUPT` is a service-side immutable-data incident; do not treat it as invalid participant source and do not accept partial bytes.

## Errors

| Error | When |
| :--- | :--- |
| `404 NOT_FOUND` | The item does not exist, is inactive or invisible, or is not a Lean Kernel package. |
| `500 ARTIFACT_CORRUPT` | The immutable package is missing or fails representation, Workspace, manifest, UTF-8, file-tree, byte-count, or digest validation. No package bytes are returned. |
| `503 PUBLICATION_STORE_BUSY` | The immutable publication store is temporarily busy. Retry the same read. |

See [Errors](../../../errors.md) for shared authentication, scope, and account-rate-limit errors.
