# Get label progress

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

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

Returns the frozen official participant-submission coverage grouped by transitive-group label `24Tt` and signature `r`. It never includes post-event validation discoveries and must not be used to decide whether a pair has been found after the official deadline.

This is a bulk aggregate endpoint. It returns cursor-paginated `labels[]` rather than the usual `items[]`, and exposes no team identities, submissions, or polynomial coefficients.

## Query parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `label` | string | No | Repeatable canonical-label filter, for example `?label=24T1&label=24T3`. Each value must be `24Tt`, where `1 <= t <= 25000`. |
| `labels` | string | No | Comma-separated canonical-label filter. It is merged with all `label` values; surrounding whitespace, blank entries, and duplicates are ignored. |
| `includeEmpty` | boolean | No | Default `true`. When `false`, omit labels with no officially credited participant signature. |
| `limit` | integer | No | Default `100`; minimum `1`, maximum `5000`. |
| `cursor` | string | No | Opaque cursor returned as `nextCursor` by the previous page. |

With no surviving `label` or `labels` value, the endpoint traverses the complete 25,000-label universe. Labels are ordered by ascending `t`; all signature arrays are ordered by ascending `r`.

A cursor is valid only with the same normalized label-filter set and the same `includeEmpty` value used to create it. Changing either filter and reusing the cursor returns `400 MALFORMED_BODY`.

## Response fields

| Field | Type | Description |
| :--- | :--- | :--- |
| `generatedAt` | string | ISO 8601 UTC time when this response page was generated. It is not a dataset version or discovery timestamp. |
| `labels[]` | [Label progress](#label-progress)[] | Page of official label aggregates, ordered by ascending `t`. Empty while `meta.published` is `false`. |
| `nextCursor` | string \| null | Cursor for the next page, or `null` when this traversal is complete. |
| `meta.published` | boolean | Whether the frozen official progress projection is published. |
| `meta.publishedAt` | string \| null | ISO 8601 UTC publication time, or `null` while unpublished. |

While official progress is unpublished, the endpoint still returns `200 OK` with `labels: []`, `nextCursor: null`, `meta.published: false`, and `meta.publishedAt: null`.

### Label progress

| Field | Type | Description |
| :--- | :--- | :--- |
| `label` | string | Canonical transitive-group label `24Tt`, for example `24T25000`. |
| `t` | integer | Numeric transitive-group position in the range `1` through `25000`. |
| `allowedR` | integer[] | Canonical valid signatures for this label. |
| `teamCount` | integer | Distinct non-baseline participant teams credited with at least one official signature under this label. A team credited under multiple signatures is counted once. |
| `minimumDiscAbs` | string \| null | Smallest official scoring discriminant credited under this label, as an unsigned decimal string; `null` when no signature is discovered. It is the exact number-field discriminant or the mixed-discriminant fallback used by official scoring, not the submitted polynomial discriminant. |
| `discoveredSignatures` | integer[] | Values from `allowedR` with at least one officially credited non-baseline participant team. |
| `remainingSignatures` | integer[] | Complement of `discoveredSignatures` within `allowedR`. A value here means no officially credited participant discovery; it makes no claim about mathematical existence or post-event validation discoveries. |
| `signatures[]` | [Signature progress](#signature-progress)[] | Per-signature official breakdown. |

### Signature progress

| Field | Type | Description |
| :--- | :--- | :--- |
| `r` | integer | Signature from the parent label's `allowedR`. |
| `teamCount` | integer | Distinct non-baseline participant teams officially credited for this `(t, r)` pair. |
| `minimumDiscAbs` | string \| null | Smallest official scoring discriminant for this pair, as an unsigned decimal string; `null` when undiscovered. It uses the same exact-or-mixed scoring value as the label-level minimum. |
| `discovered` | boolean | Whether at least one non-baseline participant team is officially credited for this pair. |

## Example request

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

## Example response

The generated time, team counts, discriminant, and publication time below illustrate the response shape. Use the values returned by the live endpoint.

```json
{
  "ok": true,
  "data": {
    "generatedAt": "2026-08-31T02:15:00Z",
    "labels": [
      {
        "label": "24T25000",
        "t": 25000,
        "allowedR": [0],
        "teamCount": 2,
        "minimumDiscAbs": "12345678901234567890",
        "discoveredSignatures": [0],
        "remainingSignatures": [],
        "signatures": [
          {
            "r": 0,
            "teamCount": 2,
            "minimumDiscAbs": "12345678901234567890",
            "discovered": true
          }
        ]
      }
    ],
    "nextCursor": null,
    "meta": {
      "published": true,
      "publishedAt": "2026-06-18T02:50:30Z"
    }
  }
}
```

The official dataset is frozen, so paging does not incorporate newly accepted post-event validation results. `generatedAt` is evaluated independently for each response page and can differ during one traversal without indicating that the official records changed.

Use [Get remaining pairs](./get-remaining-pairs.md) when a search client needs the same official uncovered set flattened into one `(t, r)` item per row.

## Errors

| HTTP | Code | When |
| :---: | :--- | :--- |
| `400` | `MALFORMED_BODY` | `limit` or `includeEmpty` is malformed, the cursor cannot be decoded, or the cursor is reused with different normalized filters. |
| `404` | `NOT_FOUND` | IGP24 does not exist or is not publicly visible. |
| `422` | `RESOURCE_FIELD_INVALID` | A `label` or `labels` entry is not a valid `24Tt` label in the supported range. |
| `503` | `IGP24_SERVICE_UNAVAILABLE` | The frozen official progress service is temporarily unavailable. |

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