# Get a submission by ID

```http
GET /api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage2/submissions/{submissionId}
```

**Scope**: `competition.read`.

Returns one current Stage 2 solver entry by its opaque public ID. The entry must belong to the caller's active competition team; any active team member may read it, including the stored `solverCode`.

Obtain `submissionId` from [List my submissions](./list-my-submissions.md). Pass it through unchanged.

## Path parameter

| Parameter | Type | Description |
| :-------- | :--- | :---------- |
| `submissionId` | string | Exact, case-sensitive public ID returned by a submission endpoint. |

## Example request

```bash
curl "https://api.sair.foundation/api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage2/submissions/sub_01JSTAGE200000000000000001" \
  -H "Authorization: Bearer $SAIR_API_KEY"
```

## Example response

```json
{
  "ok": true,
  "data": {
    "submissionId": "sub_01JSTAGE200000000000000001",
    "competitionId": "mathematics-distillation-challenge-equational-theories-stage2",
    "kind": "solver-participation",
    "payload": {
      "track": "solo",
      "modelId": "openai-gpt-oss-120b",
      "solverCode": "import json\ncontext = json.loads(input())\nprint(json.dumps({\"call\": \"judge\", \"verdict\": \"true\", \"code\": \"by rfl\"}), flush=True)\njudge_result = json.loads(input())"
    },
    "meta": {
      "description": "Reflexive Solo baseline."
    },
    "createdAt": "2026-05-18T12:34:56Z",
    "updatedAt": "2026-05-18T12:34:56Z"
  }
}
```

The short solver illustrates the stored response shape, not a general competition strategy.

## Response fields

| Field | Type | Description |
| :---- | :--- | :---------- |
| `submissionId` | string | Stable public ID for this team, track, and model combination. |
| `competitionId` | string | Competition that owns the entry; it matches the route's competition ID. |
| `kind` | `solver-participation` | Submission discriminator. |
| `payload.track` | string | Track selected for this entry. |
| `payload.modelId` | string | Model selected for this entry. Together with `track`, it identifies the entry. |
| `payload.solverCode` | string | Exact stored Python source. |
| `meta.description` | string | Optional submission note; omitted when absent. |
| `meta.contributorNetworkItemId` | string | Optional Contributor Network attribution; omitted when absent. |
| `createdAt` | string | ISO 8601 UTC creation time of this stable pair entry. |
| `updatedAt` | string | ISO 8601 UTC time of its latest accepted replacement. |

## Resource behavior

- Replacing the same `(track, modelId)` pair with a new idempotency key updates this resource in place. Its `submissionId` and `createdAt` remain stable; `updatedAt`, `payload`, and `meta` reflect the latest accepted replacement.
- Replaying the same idempotency key does not mutate the resource.
- The ID is resolved inside the competition named in the URL and against the caller's current active team. Moving the ID to another competition URL, using another team's ID, having no active team, or leaving the team all produce the same not-found response.
- Use [Download a submission](./download-submission.md) when the solver source is needed as a plain-text file rather than JSON.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `404` | `NOT_FOUND` | The competition is not publicly visible, the submission does not exist in that competition, or it is not accessible to the caller's current active team. |

These cases intentionally share one response so the endpoint does not reveal whether another team's submission exists. Shared authentication, scope, and rate-limit errors are documented in [Errors](../../../errors.md).
