# Download a Run source snapshot

```http
GET /api/public/v1/competitions/lean-kernel-challenge/playground/runs/{runId}/download
```

**Scope**: `playground.read`.

Downloads the exact immutable user Workspace captured for one Playground Run owned by the caller.

The snapshot is available as soon as the Run is recorded. Download does not wait for evaluation or contact the evaluator, so `pending`, `running`, `done`, and `failed` Runs use the same operation. Existing snapshots remain readable after unenrollment, Playground read-only mode, or Competition closure. Team membership does not grant access to another account's Run.

## Path parameter

| Parameter | Type, requirement, and meaning |
| :--- | :--- |
| `runId` | **Required string.** Opaque Run ID returned by [Create a Playground run](./create-playground-run.md), [List Playground runs](./list-playground-runs.md), or [Get a Playground run](./get-playground-run.md). Pass it through unchanged. |

## Snapshot contents

The response contains the exact user files captured by the Run, not the current contents of its saved Solution. Later Solution edits do not change the download.

- A snapshot containing only `Submission.lean` is returned as its original UTF-8 source bytes.
- A snapshot with auxiliary files is returned as a ZIP whose root mirrors the complete normalized Workspace path tree, including `Submission.lean`.
- The download does not include official dependencies, build artifacts, compiled output, caches, logs, public practice inputs, measurements, results, server paths, credentials, or runtime configuration.

The server validates the stored manifest and the snapshot's Run, Solution, revision, Problem, rule, template, and toolchain binding before returning any bytes. Clients must treat a source-integrity error as a service incident, not as an invalid participant file.

## Example request

```bash
export SAIR_API_BASE="https://api.sair.foundation/api/public/v1"
export SAIR_RUN_ID="31"

curl -OJ \
  "$SAIR_API_BASE/competitions/lean-kernel-challenge/playground/runs/$SAIR_RUN_ID/download" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

`-OJ` saves the attachment using the server-provided filename. Automated clients should use `Content-Type` to select a decoder and must not parse metadata from the filename.

## Successful response

This endpoint returns file bytes directly, not the standard JSON success envelope.

For a single-file snapshot:

```http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="lean-kernel-fib-practice-run-31.lean"
Content-Length: 1842
X-Content-Type-Options: nosniff
```

For a multi-file snapshot, `Content-Type` is `application/zip` and the attachment filename ends in `.zip`.

| 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 a server-generated attachment filename ending in `.lean` or `.zip`. Treat it as display and save metadata, not as a source of Run fields. |
| `Content-Length` | Exact number of response-body bytes. The value above is illustrative. |
| `X-Content-Type-Options` | `nosniff` prevents content-type guessing. |

Do not decode an `application/zip` response as text. Save it as a ZIP or inspect its validated relative file tree with a ZIP-aware client. Extracted source bytes and paths reproduce the Run's user Workspace; the archive itself is not a bundle of the official toolchain or evaluator environment.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `404` | `NOT_FOUND` | The Competition or Run does not exist, is not visible, or is not owned by the caller. The response does not distinguish these cases. |
| `409` | `RUN_SOURCE_INTEGRITY_FAILED` | The immutable snapshot is corrupt, incomplete, bound to different Run metadata, or cannot be packaged safely. No source bytes are returned. |
| `410` | `RUN_SOURCE_MISSING` | The retained Run exists, but its immutable source snapshot is no longer available. |
| `500` | `RUN_SOURCE_READ_FAILED` | The private snapshot store could not read or reconstruct the immutable source. |
| `502` | `PLATFORM_UNAVAILABLE` | Competition visibility cannot be verified. |
| `503` | `RUN_STORE_BUSY` | The private Run snapshot store is temporarily busy. Retry the same read. |

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