# Inverse Galois Problem (IGP24)

Competition ID: `igp24`

Use this guide when planning Inverse Galois Problem (IGP24) searches and automating formal polynomial submissions.

## Endpoint map

Use `competitionId = igp24`.

**Competition endpoints**

| Task | Endpoint | Scope | Notes |
| :--- | :--- | :--- | :--- |
| Read schema | [`GET /api/public/v1/competitions/igp24`](./api/get-competition.md#inverse-galois-problem-igp24) | `competition.read` | Complete IGP24 `submissionSpec`. |
| Check participation | [`GET /api/public/v1/competitions/igp24/me`](./api/get-my-participation.md#inverse-galois-problem-igp24) | `competition.read` | Active members may submit. |
| Read label progress | [`GET /api/public/v1/competitions/igp24/labels/progress`](#label-progress) | `competition.read` | Aggregate participant progress by label and signature. |
| Read remaining pairs | [`GET /api/public/v1/competitions/igp24/remaining-pairs`](#remaining-pairs) | `competition.read` | Canonical pairs not yet discovered by a participant team. |
| Create a new submission | [`POST /api/public/v1/competitions/igp24/submissions`](./api/submit.md#inverse-galois-problem-igp24) | `competition.write` | Each call creates a fresh `submissionId`. |
| Poll submission verification | [`GET /api/public/v1/competitions/igp24/submissions/batch/{batchId}`](./api/get-submission-batch-status.md) | `competition.read` | Per-polynomial status for the submitted `batchId`. |
| Get my submissions | [`GET /api/public/v1/competitions/igp24/submissions/mine`](./api/list-my-submissions.md#inverse-galois-problem-igp24) | `competition.read` | Unified collection endpoint; newest first and cursor-paginated. |
| Get my submissions (legacy) | [`GET /api/public/v1/competitions/igp24/submissions/me`](./api/get-my-submission-legacy.md#inverse-galois-problem-igp24) | `competition.read` | Existing IGP24 collection contract remains unchanged. |
| Read a submission by ID | [`GET /api/public/v1/competitions/igp24/submissions/{submissionId}`](./api/get-submission.md#inverse-galois-problem-igp24) | `competition.read` | JSON omits coefficient strings. |
| Download | [`GET /api/public/v1/competitions/igp24/submissions/{submissionId}/download`](./api/download-submission.md#inverse-galois-problem-igp24) | `competition.read` | Returns polynomial lines as `text/plain`. |
| Read leaderboard | [`GET /api/public/v1/competitions/igp24/leaderboard`](./api/get-leaderboard.md#igp24-example) | `competition.read` | Cursor-paginated public ranking. |
| Read my standing | [`GET /api/public/v1/competitions/igp24/leaderboard/me`](./api/get-my-standing.md#igp24-example) | `competition.read` | Current caller's public ranking. |
| Read team placements | [`GET /api/public/v1/competitions/igp24/leaderboard/teams/{teamId}/placements`](./api/get-team-placements.md) | `competition.read` | Cursor-paginated public placements for one team. |
| Search leaderboard placements | [`GET /api/public/v1/competitions/igp24/leaderboard/search`](./api/search-leaderboard.md) | `competition.read` | Match placements by `t`, `r`, or both. |

IGP24 is not supported by Playground. Submit polynomial batches through [`POST /api/public/v1/competitions/igp24/submissions`](./api/submit.md#inverse-galois-problem-igp24).

## Rate limit

IGP24 submissions are shared across the competition website and API. Each team starts with **5 submissions per day**. After the team has been credited with at least **5 distinct scoreable `(24Tt, r)` pairs**, its cap increases to **1000 submissions per day**. Each `POST /submissions` counts as one submission regardless of how many polynomials it carries. Exceeding the active cap returns `429` with `IGP24_SUBMISSION_RATE_LIMIT_EXCEEDED` and a `Retry-After` header; pace yourself using the `X-RateLimit-*` headers. See [Rate limiting](../../rate-limiting.md).

## Label progress

```http
GET /api/public/v1/competitions/igp24/labels/progress
```

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

Returns aggregate participant progress for IGP24, grouped by transitive group label and real-root count/signature `r`. It is designed for search planning and batch analysis without scraping the competition website.

This is a bulk aggregate endpoint. It intentionally returns `labels[]` rather than the usual `items[]`, and its page-size maximum is higher than the default list endpoint maximum so clients can traverse the 25,000-label IGP24 universe efficiently.

### Query parameters

| Parameter      | Type    | Required | Description |
| :------------- | :------ | :------: | :---------- |
| `cursor`       | string  | No       | Opaque cursor from the previous `nextCursor`. |
| `limit`        | integer | No       | Number of labels to return. Default `100`, maximum `5000`. |
| `label`        | string  | No       | Repeatable label filter, e.g. `?label=24T1&label=24T3`. |
| `labels`       | string  | No       | Comma-separated label filter, e.g. `?labels=24T1,24T3,24T25000`. |
| `includeEmpty` | boolean | No       | Defaults to `true`. When `false`, only labels with at least one discovered signature are returned; returned labels still include their full signature breakdown. |

Filters are applied before the cursor. Changing `label`, `labels`, or `includeEmpty` invalidates a previous cursor; start a new traversal when filters change.

### Response fields

| Field         | Type                                                 | Description |
| :------------ | :--------------------------------------------------- | :---------- |
| `generatedAt` | string                                               | ISO 8601 UTC timestamp for the generated page. |
| `labels[]`    | [Igp24LabelProgress](#igp24-label-progress-fields)[] | Label-level aggregate progress records. Empty when `meta.published` is `false`. |
| `nextCursor`  | string \| null                                       | Cursor for the next page, or `null`. |
| `meta`        | [Igp24ProgressMeta](#igp24-progress-metadata-fields) | Publication state for the progress data. |

### IGP24 progress metadata fields

| Field         | Type           | Description |
| :------------ | :------------- | :---------- |
| `published`   | boolean        | Whether IGP24 leaderboard/progress data is currently published. |
| `publishedAt` | string \| null | ISO 8601 UTC publication timestamp, or `null` when unpublished. |

### IGP24 label progress fields

| Field                  | Type                                                        | Description |
| :--------------------- | :---------------------------------------------------------- | :---------- |
| `label`                | string                                                      | Transitive group label, e.g. `24T25000`. |
| `t`                    | integer                                                     | Numeric transitive group index. |
| `allowedR`             | integer[]                                                   | All allowed real-root counts/signatures for this label. |
| `teamCount`            | integer                                                     | Number of distinct participant teams currently credited with this label. The display-only LMFDB baseline/system team is not counted. |
| `minimumDiscAbs`       | string \| null                                              | Minimum absolute scoring discriminant currently credited for this label, or `null` when undiscovered. This is not the submitted polynomial discriminant. |
| `discoveredSignatures` | integer[]                                                   | Allowed `r` values discovered by at least one participant team. |
| `remainingSignatures`  | integer[]                                                   | Allowed `r` values not yet discovered by a participant team. |
| `signatures[]`         | [Igp24SignatureProgress](#igp24-signature-progress-fields)[] | Per-`r` progress records for this label. |

### IGP24 signature progress fields

| Field            | Type           | Description |
| :--------------- | :------------- | :---------- |
| `r`              | integer        | Real-root count/signature. |
| `teamCount`      | integer        | Number of distinct participant teams currently credited with this `(label, r)`. |
| `minimumDiscAbs` | string \| null | Minimum absolute scoring discriminant currently credited for this `(label, r)`, or `null` if undiscovered. This is not the submitted polynomial discriminant. |
| `discovered`     | boolean        | Whether this `(label, r)` has been discovered by a participant team. |

These progress fields reflect participant-team discoveries. LMFDB baseline records do not affect them.

Each response is generated as a short-lived page-level snapshot. Responses may be cached for up to 120 seconds per distinct query. The endpoint does not guarantee one stable global snapshot across a multi-page traversal; results are eventually consistent and may change between pages.

For batch analysis, request up to `limit=5000` and continue with `nextCursor` until it is `null`. The full IGP24 label set contains 25,000 labels, so the complete dataset can be retrieved in approximately five paginated requests at the maximum page size.

**Example request**

```bash
curl -H "Authorization: Bearer $SAIR_API_KEY" \
  "https://api.sair.foundation/api/public/v1/competitions/igp24/labels/progress?limit=1000"
```

**Example response**

```json
{
  "ok": true,
  "data": {
    "generatedAt": "2026-06-23T05:30:11Z",
    "labels": [
      {
        "label": "24T25000",
        "t": 25000,
        "allowedR": [0, 2, 4],
        "teamCount": 5,
        "minimumDiscAbs": "12345678901234567890",
        "discoveredSignatures": [0, 2],
        "remainingSignatures": [4],
        "signatures": [
          {
            "r": 0,
            "teamCount": 2,
            "minimumDiscAbs": "12345678901234567890",
            "discovered": true
          },
          {
            "r": 2,
            "teamCount": 3,
            "minimumDiscAbs": "22345678901234567890",
            "discovered": true
          },
          {
            "r": 4,
            "teamCount": 0,
            "minimumDiscAbs": null,
            "discovered": false
          }
        ]
      }
    ],
    "nextCursor": null,
    "meta": {
      "published": true,
      "publishedAt": "2026-06-18T02:50:30Z"
    }
  }
}
```

### Errors

See [Errors](../../errors.md) for the full code table. Endpoint-specific:

| Code                     | HTTP | When |
| :----------------------- | :--: | :--- |
| `MALFORMED_BODY`         | 400  | `limit` is outside `1..5000`, a query parameter cannot be parsed, or the cursor is malformed while progress is published. |
| `RESOURCE_FIELD_INVALID` | 422  | A label filter is semantically invalid, e.g. it does not use the `24Tt` form. |

## Remaining pairs

```http
GET /api/public/v1/competitions/igp24/remaining-pairs
```

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

Returns canonical valid `(24Tt, r)` pairs not yet discovered by a participant team.

### Query parameters

| Parameter | Type    | Required | Description |
| :-------- | :------ | :------: | :---------- |
| `cursor`  | string  | No       | Opaque cursor from the previous `nextCursor`. |
| `limit`   | integer | No       | Number of pairs to return. Default `100`; minimum `1`, maximum `5000`. |

### Response fields

| Field         | Type                                                           | Description |
| :------------ | :------------------------------------------------------------- | :---------- |
| `generatedAt` | string                                                         | ISO 8601 UTC timestamp for the generated page. |
| `items[]`     | [Igp24RemainingPair](#igp24-remaining-pair-fields)[]           | Pairs not yet discovered by a participant team, ordered by ascending `(t, r)`. |
| `nextCursor`  | string \| null                                                 | Cursor for the next page, or `null`. |
| `meta`        | [Igp24ProgressMeta](#igp24-progress-metadata-fields)           | Publication state for the remaining-pair data; when `published` is `false`, `items` is empty. |

### IGP24 remaining-pair fields

| Field   | Type    | Description |
| :------ | :------ | :---------- |
| `label` | string  | Transitive group label, e.g. `24T25000`. |
| `t`     | integer | Numeric transitive group index. |
| `r`     | integer | Allowed real-root count/signature for the label. |

Pairs are ordered by ascending `t`, then ascending `r`. Continue until `nextCursor` is `null` to traverse all matching pairs.


Each response is a page-level snapshot. Participant progress may change between pages, so a multi-page traversal is eventually consistent rather than a single frozen global snapshot.

**Example request**

```bash
curl -H "Authorization: Bearer $SAIR_API_KEY" \
  "https://api.sair.foundation/api/public/v1/competitions/igp24/remaining-pairs?limit=1000"
```

**Example response**

```json
{
  "ok": true,
  "data": {
    "generatedAt": "2026-07-13T10:30:00Z",
    "items": [
      {
        "label": "24T100",
        "t": 100,
        "r": 2
      },
      {
        "label": "24T100",
        "t": 100,
        "r": 6
      }
    ],
    "nextCursor": "WzEwMCw2XQ==",
    "meta": {
      "published": true,
      "publishedAt": "2026-06-18T02:50:30Z"
    }
  }
}
```

### Errors

See [Errors](../../errors.md) for the full code table. Endpoint-specific:

| Code             | HTTP | When |
| :--------------- | :--: | :--- |
| `MALFORMED_BODY` | 400  | `limit` is outside `1..5000`, a query parameter cannot be parsed, or the cursor is malformed while progress is published. |

## Submission payload

The competition uses `submissionSpec.kind: "igp24-polynomial"`.

Read `submissionSpec.permission` from the competition detail before submitting. For IGP24 it is `teamRole: "activeMember"`, so any active member of the IGP24 team may submit polynomial batches.

**Example request body**

```json
{
  "payload": {
    "polynomials": [
      "3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 # poly_disc_primes=[2,3]",
      "1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1"
    ]
  },
  "meta": {
    "description": "Adapted from a public polynomial table; reproduction script: search batch 12."
  }
}
```

Payload fields:

- `payload.polynomials[]` is required. Each item is one candidate polynomial line in the official submission-text format.
- `meta.description` is optional and capped by `submissionSpec.metaSchema.properties.description.maxLength` (currently 500 characters for IGP24). Use it for provenance, source citations, or reproduction notes.

Before any trailing `#` comment, each polynomial line must contain exactly 25 comma-separated integers in ascending powers: `a_0,a_1,...,a_24`. `a_0` must be nonzero, `a_24` must be `1` (submissions must be monic), and the coefficient gcd must be `1`.

The Public API accepts JSON only; it does not upload an IGP24 file. Blank lines and full-line comments are not items in `payload.polynomials[]`. A valid polynomial string may include a trailing `#` comment. Ordinary trailing comments are preserved with the submitted line but ignored by verification.

The exact trailing-comment body `poly_disc_primes=[...]` supplies an optional prime-factor ramp hint for `quicknfdisc`:

```text
3,0,...,0,1 # poly_disc_primes=[2,3]
```

List known prime factors as strictly increasing decimal integers greater than 1, without exponents. Values are transported as text and may exceed the JavaScript safe-integer range. The list may be incomplete. Additional prose in the same comment prevents the reserved field from being recognized. A malformed, structurally invalid, or otherwise unusable hint is silently ignored; if the acceleration path is unavailable, the ordinary discriminant workflow also continues. Neither case rejects an otherwise valid polynomial or changes its Magma verification result. The persisting submissions endpoint accepts hints; dry-run verification endpoints ignore them because they do not compute discriminants.

The maximum accepted count is published as `submissionSpec.limits.maxPolynomials`.

The size cap is published as `submissionSpec.limits.maxBytes`. The canonical limit is the raw `submission.txt` body size: 1,000,000 bytes. For IGP24 Public API requests, join the complete `payload.polynomials` strings, including trailing comments, with newline separators and measure the UTF-8 byte length.

The separately published `submissionSpec.limits.maxRequestBytes` limit (currently 1,310,720 bytes) applies to the normalized JSON request envelope, including `payload`, `meta`, and JSON quoting or escaping overhead. Requests must satisfy both byte limits.

## Submit

```bash
curl -X POST "https://api.sair.foundation/api/public/v1/competitions/igp24/submissions" \
  -H "Authorization: Bearer $SAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "payload": {
      "polynomials": [
        "3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 # poly_disc_primes=[2,3]",
        "1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1"
      ]
    },
    "meta": {
      "description": "Adapted from a public polynomial table; reproduction script: search batch 12."
    }
  }'
```

Validation starts during submission and may continue asynchronously. Submission responses and subsequent reads expose `verifiedPolynomials`, `failedPolynomials`, and `payload.queuedPolynomials`; accepted records include `label`, `t`, and `r` once verification completes. Result items do not echo coefficient strings or expose `prime_hint_status` or `nfdisc_method`. Use the download endpoint to retrieve submitted lines for a submission accessible to the caller; current IGP24 team submissions are team-scoped. Duplicate canonical polynomials are verified and stored only once internally, using the first occurrence's prime hint, while every input index is still represented in the verified, failed, or queued result lists.

## Download submitted polynomials

```bash
curl "https://api.sair.foundation/api/public/v1/competitions/igp24/submissions/$SUBMISSION_ID/download" \
  -H "Authorization: Bearer $SAIR_API_KEY" \
  -o "igp24-$SUBMISSION_ID-polynomials.txt"
```

The response is `text/plain; charset=utf-8` and contains the original submitted polynomial strings for that submission, one polynomial per line, including any trailing comments. It does not include verification results, labels, computed discriminants, or submission metadata.

See [Submission kinds](../../reference/submission-kinds.md#igp24-polynomial) for the full DTO.

See [Competitions](../competitions.md) for the shared endpoint field tables.
