# Submit cheatsheet

```http
POST /api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage1/submissions
Content-Type: application/json
```

**Scope**: `competition.write`.

Creates the team's first formal Stage 1 cheatsheet or replaces its current cheatsheet. Only the team owner—or a solo participant represented as the owner of a one-person team—may submit. Stage 1 stores one current entry rather than append-only submission history.

Before submitting, read [Get competition detail](./get-competition-detail.md) for the live schema and limits, then confirm [Get my participation](./get-my-participation.md) returns `canSubmit: true`.

## Request body

```ts
type SubmitCheatsheetRequest = {
  idempotencyKey: string;
  payload: {
    content: string;
  };
  meta?: {
    description?: string;
    contributorNetworkItemId?: string;
  };
};
```

| Field | Required | Description |
| :---- | :------: | :---------- |
| `idempotencyKey` | Yes | Non-empty client-generated key, at most 200 UTF-8 bytes after surrounding whitespace is removed. |
| `payload.content` | Yes | Cheatsheet text. It must be non-empty and fit within the live `submissionSpec.limits.maxBytes`. |
| `meta.description` | No | Human-readable submission note, subject to `submissionSpec.metaSchema`. |
| `meta.contributorNetworkItemId` | No | Lineage reference to an active Contributor Network item from this competition. It does not copy that item's content. |

## Idempotency

Generate a new opaque `idempotencyKey` once for each intended formal submission or replacement. Reuse that same key only when retrying the exact same `payload` and `meta` after a timeout or uncertain response.

An exact replay returns the previously recorded operation with `200 OK` and does not queue another evaluation. Reusing the key with different content or metadata returns `409 IDEMPOTENCY_CONFLICT`. A new key represents a deliberate replacement of the current formal cheatsheet.

## Example request

```bash
export SAIR_IDEMPOTENCY_KEY="stage1-submit-$(openssl rand -hex 16)"

curl -X POST "https://api.sair.foundation/api/public/v1/competitions/mathematics-distillation-challenge-equational-theories-stage1/submissions" \
  -H "Authorization: Bearer $SAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "'"$SAIR_IDEMPOTENCY_KEY"'",
    "payload": {
      "content": "When the equation has a neutral element, test substitutions that preserve it before expanding the search."
    },
    "meta": {
      "description": "Playground-tested cheatsheet.",
      "contributorNetworkItemId": "cn_01JSTAGE100000000000000001"
    }
  }'
```

## Response

The first formal entry returns `201 Created`. A new logical operation that replaces the current entry returns `200 OK`; the stable `submissionId` is retained. An exact idempotency replay also returns `200 OK` without changing the entry or starting another evaluation.

```json
{
  "ok": true,
  "data": {
    "submissionId": "sub_01JSTAGE100000000000000001",
    "competitionId": "mathematics-distillation-challenge-equational-theories-stage1",
    "kind": "cheatsheet",
    "payload": {
      "content": "When the equation has a neutral element, test substitutions that preserve it before expanding the search."
    },
    "meta": {
      "description": "Playground-tested cheatsheet.",
      "contributorNetworkItemId": "cn_01JSTAGE100000000000000001"
    },
    "createdAt": "2026-05-18T12:34:56Z",
    "updatedAt": "2026-05-18T12:34:56Z"
  }
}
```

`createdAt` remains the creation time of the stable formal entry. `updatedAt` changes only when a new logical replacement is accepted, not when the same idempotency key is replayed.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `400` | `IDEMPOTENCY_KEY_REQUIRED` | `idempotencyKey` is missing or empty. |
| `400` | `IDEMPOTENCY_KEY_TOO_LONG` | `idempotencyKey` exceeds 200 UTF-8 bytes. |
| `403` | `ENROLL_REQUIRED` | The caller has not completed enrollment. |
| `403` | `EMAIL_NOT_VERIFIED` | The caller's email is not verified. |
| `403` | `TEAM_OWNER_REQUIRED` | The caller is an invited team member rather than the owner. |
| `403` | `SUBMISSION_WINDOW_NOT_OPEN` | The formal submission window has not opened. |
| `403` | `SUBMISSION_WINDOW_CLOSED` | The formal submission window has closed. |
| `409` | `IDEMPOTENCY_CONFLICT` | The same key was already used with a different request. |
| `413` | `FILE_TOO_LARGE` | `payload.content` exceeds the live byte limit. |
| `422` | `SUBMISSION_PAYLOAD_INVALID` | `payload` does not match `submissionSpec.schema`. |
| `422` | `SUBMISSION_META_INVALID` | `meta` does not match `submissionSpec.metaSchema` or references an invalid Contributor Network item. |

See [Errors](../../../errors.md) for authentication, authorization, rate limits, and the standard error envelope.
