# Cheatsheet library

Manage the calling account's private Stage 1 cheatsheets. A cheatsheet can be selected in a [Stage 1 Playground Run](./create-playground-run.md) through `configurations[].cheatsheet`.

The library is independent of the formal competition entry. It may contain multiple cheatsheets, while the [formal submission endpoint](./submit-cheatsheet.md) stores one current entry by copying submitted content. Updating or deleting a library cheatsheet does not change that formal entry.

## Lifecycle

| State | Editable | Behavior |
| :--- | :---: | :--- |
| Private | Yes | The owner may read, update, delete, or use the cheatsheet in Playground Runs. |
| Published | No | `publishedContributorNetworkItemId` identifies the active Contributor Network item. Withdraw that item before updating or deleting the source cheatsheet. |
| Withdrawn | Yes | The private cheatsheet remains, and `publishedContributorNetworkItemId` returns to `null`. It may be edited and published again. |

`sourceContributorNetworkItemId` records the active Stage 1 Contributor Network item from which a cheatsheet was derived. It is set at creation and is immutable. A later publication uses this value as its lineage parent; see [Publish a cheatsheet](./publish-contributor-cheatsheet.md).

An account may store at most 20 cheatsheets, including published cheatsheets. The daily creation quota is documented under [Daily resource creation](../../../rate-limiting.md#daily-resource-creation); deleting a cheatsheet frees library capacity but does not restore that day's creation quota.

## Cheatsheet fields

List responses return `CheatsheetSummary`; item, create, and update responses return `Cheatsheet`, which adds `content`.

| Field | Type | Included | Description |
| :--- | :--- | :--- | :--- |
| `id` | string | All responses | Stable cheatsheet ID. |
| `title` | string | All responses | Trimmed title. |
| `sourceContributorNetworkItemId` | string \| null | All responses | Contributor Network item recorded when this cheatsheet was derived, or `null`. |
| `publishedContributorNetworkItemId` | string \| null | All responses | Active item published from this cheatsheet, or `null`. |
| `createdAt` | string | All responses | ISO 8601 UTC creation time. |
| `updatedAt` | string | All responses | ISO 8601 UTC time of the latest title or content update. |
| `content` | string | Item responses only | Cheatsheet body. Omitted from list responses. |

## List cheatsheets

```http
GET /api/public/v1/cheatsheets
```

**Scope**: `playground.read`. This endpoint is cursor-paginated.

Returns only cheatsheets owned by the calling account, ordered by creation time from newest to oldest. Updating a cheatsheet does not move it to the front of the list. Follow the shared [cursor traversal rules](../../../pagination.md).

### Query parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `cursor` | string | No | Opaque cursor from the previous `nextCursor`. |
| `limit` | integer | No | Page size. Default `25`, maximum `100`. |

### Response fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `items` | [CheatsheetSummary](#cheatsheet-fields)[] | Cheatsheet summaries without `content`. |
| `nextCursor` | string \| null | Cursor for the next page, or `null` after the final page. |

```json
{
  "ok": true,
  "data": {
    "items": [
      {
        "id": "cs_01JSTAGE100000000000000001",
        "title": "Prime modulus shortcuts",
        "sourceContributorNetworkItemId": "cn_01JSTAGE100000000000000007",
        "publishedContributorNetworkItemId": null,
        "createdAt": "2026-04-12T08:21:30Z",
        "updatedAt": "2026-05-04T17:02:11Z"
      }
    ],
    "nextCursor": null
  }
}
```

## Get a cheatsheet

```http
GET /api/public/v1/cheatsheets/{cheatsheetId}
```

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

Returns one owned [Cheatsheet](#cheatsheet-fields), including `content`. A missing cheatsheet and a cheatsheet owned by another account both return `404 NOT_FOUND`.

### Path parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `cheatsheetId` | string | Yes | Cheatsheet ID. |

## Create a cheatsheet

```http
POST /api/public/v1/cheatsheets
Content-Type: application/json
```

**Scope**: `playground.write`.

Creates a private cheatsheet for the calling account.

### Request fields

| Field | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `title` | string | Yes | Title after trimming: 1–200 characters. |
| `content` | string | Yes | Body containing at least one non-whitespace character. Its UTF-8 byte length must not exceed the Stage 1 `submissionSpec.limits.maxBytes` returned by [Get competition detail](./get-competition-detail.md). |
| `sourceContributorNetworkItemId` | string | No | Active, visible Stage 1 `cheatsheet` item from which this content was derived. The reference is immutable after creation. |

```bash
curl -X POST "https://api.sair.foundation/api/public/v1/cheatsheets" \
  -H "Authorization: Bearer $SAIR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "title": "Prime modulus shortcuts",
    "content": "When the modulus is prime, apply Fermat’s little theorem...",
    "sourceContributorNetworkItemId": "cn_01JSTAGE100000000000000007"
  }'
```

Returns `201 Created` with the created [Cheatsheet](#cheatsheet-fields), including `content`.

## Update a cheatsheet

```http
PATCH /api/public/v1/cheatsheets/{cheatsheetId}
Content-Type: application/json
```

**Scope**: `playground.write`.

Partially updates an owned private cheatsheet. Include `title`, `content`, or both; an empty request object returns `422 RESOURCE_FIELD_INVALID`. `sourceContributorNetworkItemId` cannot be changed.

The title and content constraints are the same as for [Create a cheatsheet](#create-a-cheatsheet). A published source returns `403 CHEATSHEET_LOCKED`; withdraw its Contributor Network item before editing it.

### Path parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `cheatsheetId` | string | Yes | Cheatsheet ID. |

### Request fields

| Field | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `title` | string | No | Replacement title. |
| `content` | string | No | Replacement body. |

```bash
curl -X PATCH "https://api.sair.foundation/api/public/v1/cheatsheets/$CHEATSHEET_ID" \
  -H "Authorization: Bearer $SAIR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "title": "Prime modulus shortcuts v2"
  }'
```

Returns `200 OK` with the updated [Cheatsheet](#cheatsheet-fields), including `content`.

## Delete a cheatsheet

```http
DELETE /api/public/v1/cheatsheets/{cheatsheetId}
```

**Scope**: `playground.write`.

Deletes an owned private cheatsheet and returns `204 No Content`. Deletion does not alter a formal submission or a completed Playground Run. A published source returns `403 CHEATSHEET_LOCKED`; withdraw its Contributor Network item first.

### Path parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `cheatsheetId` | string | Yes | Cheatsheet ID. |

## Errors

See [Errors](../../../errors.md). Endpoint-specific errors are:

| HTTP | Code | When |
| :---: | :--- | :--- |
| `403` | `CHEATSHEET_LOCKED` | The cheatsheet has an active Contributor Network publication. |
| `403` | `CHEATSHEET_CAP_EXCEEDED` | The account already stores 20 cheatsheets. |
| `404` | `NOT_FOUND` | The cheatsheet is missing or is not owned by the calling account. |
| `422` | `RESOURCE_FIELD_INVALID` | A field is invalid, the update is empty, or the source Contributor Network item is not an active Stage 1 cheatsheet. |
| `429` | `DAILY_RESOURCE_LIMIT_EXCEEDED` | The account exhausted the UTC-day cheatsheet creation quota. |
