---
title: "Per-Shift coverage roll-up for a recurring signup"
method: GET
path: "/signups/{id}/slot_coverage"
tags: ["Signups"]
---

# Per-Shift coverage roll-up for a recurring signup

`GET /signups/{id}/slot_coverage`

## Request

- Base URL: `https://thesignup.app/api/v1`
- URL: `https://thesignup.app/api/v1/signups/{id}/slot_coverage`
- Auth: HTTP bearer

One entry per Shift — a repeating slot in the signup's Slot Series — rolled up across every date it runs. Answers 'which Shift is chronically short across its upcoming dates?', which the flat, event-wide `/analytics` snapshot cannot. Returns an empty list (200) for a signup with no Slot Series; a non-recurring signup simply has no Shifts. Regulars carry participant names and attendance counts and NO email addresses: this is an analytics roll-up, and the capability it owes is 'who are my dependable people for this Shift'. Use `/signups/{id}/participants` under its own scope to reach anyone. Not paginated, deliberately: the roll-up averages over every Occurrence and the roster read behind it is unpaged, because an average over a page is an average of the first 50 people. It is bounded upstream instead — a Slot Series generates at most 2000 Occurrences (`MAX_OCCURRENCES` in slot-series.service.ts) and each Shift publishes at most four Regulars, so the worst case is on the order of 2000 coverage cells.

## Path parameters

- `id` string, uuid, required

## Response `200`

Coverage roll-up, one entry per Shift, ordered by `shiftIndex`

- SlotCoverageResponse
  - `data` SlotCoverageEntry[], required
    - `seriesId` string, uuid, required
    - `shiftIndex` integer, required: Position in the Series' shift plan. `(seriesId, shiftIndex)` IS the Shift.
    - `title` string, nullable, required
    - `startTime` string, date-time, required: ISO-8601 UTC, taken from the Shift's next upcoming Occurrence — or its last one once the Shift is over.
    - `endTime` string, date-time, required
    - `capacity` integer, required
    - `recurrence` SlotCoverageRecurrence, required
      - `frequency` 'daily' | 'weekly' | 'monthly', required
      - `interval` integer, required
      - `rangeStart` string, required
      - `rangeEnd` string, required
      - `occurrenceCount` integer, required: Occurrences of this Shift, cancelled ones included.
    - `averageFill` number, nullable, required: Mean `filled` across every non-cancelled Occurrence, PAST INCLUDED, to one decimal. Null when the Shift has no non-cancelled Occurrence at all — no data is not a measurement of zero.
    - `upcoming` union, required
      - object
        - `kind` 'none-left', required
      - object
        - `kind` 'some', required
        - `staffed` integer, required
        - `short` integer, required
        - `uncapped` integer, required: Upcoming Occurrences with no capacity to be at or below. On the payload so `staffed + short + uncapped` closes over the upcoming Occurrences.
        - `shortDates` string[], required: The `seriesDate`s behind `short`, so a caller never re-derives the predicate.
        - `itemsUnclaimed` integer, required: Items scoped to an upcoming Occurrence with units still needed.
    - `cells` SlotCoverageCell[], required: Every Occurrence, past and cancelled included, ordered by `seriesDate`.
      - `slotId` string, uuid, required: The `time_slots` row behind this Occurrence.
      - `seriesDate` string, required: `YYYY-MM-DD`, the Series key — not the calendar date of `startTime`.
      - `filled` integer, required
      - `capacity` integer, required: 0 means uncapped — there is no number to be at or below.
      - `isPast` boolean, required: The Occurrence's DATE is behind today in the signup's timezone. Derived per request, server-side, so every surface agrees about the same date.
      - `isCancelled` boolean, required
    - `regulars` SlotCoverageRegular[], required: Top four participants by Occurrences of this Shift taken, ties broken by name. Names and counts only — no email addresses; see the endpoint description.
      - `signupId` string, uuid, required: The participant's registration id — the handle to address them by, without an address being on this payload.
      - `name` string, required
      - `occurrencesTaken` integer, required: Distinct Occurrences of THIS Shift they hold. Per Shift, never per signup.
      - `topItemName` string, nullable, required: Their most frequent Item on this Shift's Occurrences. Null if they bring none.

## Other responses

- `401`: Unauthenticated — credentials missing, malformed, invalid, or revoked
- `404`: Not found
- `422`: Validation failed — request body / query / path is structurally wrong
- `429`: Rate limited or daily ceiling exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/thesignup/apis/thesignup-api.md) · [All operations](https://skmtc.dev/thesignup/apis/thesignup-api/llms.txt) · [OpenAPI document](https://skmtc.dev/thesignup/apis/thesignup-api/revisions/c6da7cf92172?raw)
