Programs and Series
Programs and series are two ways MLH groups related events together.
- A program is a long-running initiative that many events belong to over time (for example, an ongoing hackathon program).
- A series is a set of events run together, usually within a season, that share branding and configuration.
Individual events roll up under a program or a series: an event
points back to its program and series, and you can list all the events and
participations that belong to a series through the nested
endpoints below.
All requests are authenticated — see Authentication — and follow the shared conventions in Making requests for pagination, filtering, and expanding related data.
Programs
A program is a named, long-running MLH initiative that events belong to. Programs are read-only through the API: you can list them and fetch a single program, but you cannot create or change them here.
Endpoints
| Method | Path | What it does |
|---|---|---|
GET | /v4/programs | List programs |
GET | /v4/programs/{id} | Get one program |
Both endpoints accept expand to include related records inline, and GET /v4/programs supports the shared pagination and filtering conventions. You can
filter the list by name and slug (with operators like [eq], [contains],
and [excludes]) and by created_at / updated_at (with range operators like
[gt], [gte], [lt], [lte]). See
Making requests for the full operator list.
Fields
A program returned by these endpoints has these fields. All are read-only.
| Field | Type | Notes |
|---|---|---|
id | string | The program's unique ID. Example: "prg_a1b2c3". |
slug | string | A URL-friendly identifier for the program. Example: "season-hackathons". |
name | string | The program's display name. Example: "Season Hackathons". |
created_at | integer | When the program was created, as a Unix timestamp (seconds). |
updated_at | integer | When the program was last updated, as a Unix timestamp (seconds). |
Scopes
Requests authenticate with OAuth 2.0 or a bearer JWT, as described in Authentication. Request only the scopes your integration needs — see the full list of scopes.
Program participations
To list the participations that belong to a program, use the nested collection endpoint:
| Method | Path | What it does |
|---|---|---|
GET | /v4/programs/{program_id}/participations | List a program's participations |
The program_id path parameter is required. The endpoint is paginated (page,
limit) and supports expand[]=event and expand[]=user to include the related
event and user inline. Each participation carries the participant's status,
name, contact details, source, and links to its user and event — the same
shape documented on the Participations page.
Examples
List programs whose name contains "hack":
GET /v4/programs?name[contains]=hack&limit=50
Get one program:
GET /v4/programs/{id}
List a program's participations, expanding the user and event:
GET /v4/programs/{program_id}/participations?expand[]=user&expand[]=event
Series
A series is a group of events run together — typically within a season — that share branding and settings. Unlike programs, series support full CRUD: you can list, read, create, and update them.
Endpoints
| Method | Path | What it does |
|---|---|---|
GET | /v4/series | List series |
GET | /v4/series/{id} | Get one series |
POST | /v4/series | Create a series |
PATCH / PUT | /v4/series/{id} | Update a series |
PATCH and PUT /v4/series/{id} behave identically — both update an existing
series. GET /v4/series supports the shared pagination and filtering
conventions: you can filter by name and slug ([eq], [contains],
[excludes]) and by starts_at, ends_at, created_at, and updated_at
(range operators like [gt], [gte], [lt], [lte]). See
Making requests.
Fields
These are the fields you can set when creating or updating a series, and read
back on GET.
| Field | Required | What it does |
|---|---|---|
name | Optional | The series' display name. Example: "Fall 2026 Hackathons". |
slug | Optional | A URL-friendly identifier for the series. Example: "fall-2026". |
website_url | Optional | The series' public website. Example: "https://fall2026.example.com". |
chat_url | Optional | A link to the series' chat (for example, Discord or Slack). Example: "https://discord.gg/example". |
logo_url | Optional | A link to the series' logo image. Example: "https://cdn.example.com/logo.png". |
starts_at | Optional | When the series starts. Send as an ISO 8601 datetime string. Example: "2026-09-01T00:00:00Z". |
ends_at | Optional | When the series ends. Send as an ISO 8601 datetime string. Example: "2026-12-01T00:00:00Z". |
settings | Optional | A free-form object of series-level configuration. Example: { "theme": "dark" }. |
id | Optional | The series' ID. Read-only — the API assigns it. |
created_at | Optional | An ISO 8601 datetime string. Normally set by the API; only send it when importing historical data. |
updated_at | Optional | An ISO 8601 datetime string. Normally set by the API; only send it when importing historical data. |
A series returned by GET has the same fields, with these read/write
differences:
| Field | Type | Notes |
|---|---|---|
id | string | The series' unique ID. Read-only. |
starts_at | integer | Start time as a Unix timestamp (seconds) on reads. |
ends_at | integer | End time as a Unix timestamp (seconds) on reads. |
created_at | integer | When the series was created, as a Unix timestamp (seconds). Read-only. |
updated_at | integer | When the series was last updated, as a Unix timestamp (seconds). Read-only. |
Note the timestamp difference between reads and writes: GET responses return
starts_at, ends_at, created_at, and updated_at as Unix timestamps
(integers), while the create and update request bodies accept them as ISO 8601
datetime strings.
Scopes
Requests authenticate with OAuth 2.0 or a bearer JWT, as described in Authentication. Request only the scopes your integration needs — see the full list of scopes.
Series events
To list the events that belong to a series, use the nested collection endpoint:
| Method | Path | What it does |
|---|---|---|
GET | /v4/series/{series_id}/events | List a series' events |
The series_id path parameter is required. The endpoint is paginated (page,
limit) and supports expand[] for associations such as series, sponsors,
organizers, lead_organizer, sponsorships, prize_categories, and
event_application. Each event has the full event shape — see
Events.
Series participations
To list the participations that belong to a series, use the nested collection endpoint:
| Method | Path | What it does |
|---|---|---|
GET | /v4/series/{series_id}/participations | List a series' participations |
The series_id path parameter is required. The endpoint is paginated (page,
limit) and supports expand[]=event and expand[]=user. Each participation
carries the participant's status, name, contact details, source, and links to
its user and event — the same shape documented on the
Participations page.
Examples
Create a series:
POST /v4/series
Content-Type: application/json
{
"name": "Fall 2026 Hackathons",
"slug": "fall-2026",
"website_url": "https://fall2026.example.com",
"starts_at": "2026-09-01T00:00:00Z",
"ends_at": "2026-12-01T00:00:00Z"
}
Update a series:
PATCH /v4/series/{id}
Content-Type: application/json
{
"chat_url": "https://discord.gg/example"
}
List a series' events:
GET /v4/series/{series_id}/events?expand[]=organizers&limit=50
List a series' participations, expanding the user and event:
GET /v4/series/{series_id}/participations?expand[]=user&expand[]=event
Related
- V4 API overview
- Making requests — pagination, filtering, expanding, and errors.
- Authentication
- Events
- Participations