Developers
Heads Up offers free, read-only access to its kids'-program catalogue, one city at a time - the same public data shown on the site.
/api/{city}Search and filter the program catalogue for one city. calgary is the only city currently covered.
Query params
categoryProgram category, e.g. swimming, camps, arts.ageAge in years; matches programs whose age range includes it.areaNeighbourhood id (UUID). A name or quadrant is ignored, not matched.maxCostMaximum cost, in cents.adaptiveSet to 1 to include only adaptive/inclusive programs.qFree-text search over program name, category, venue, neighbourhood and description, falling back to a misspelling-tolerant match when nothing matches exactly.cursorPagination cursor from a previous response's meta.next_cursor.
Example request
/api/calgary/programs?category=swimming&age=6
Example response
{
"data": [
{
"id": "b3f1c2a0-...",
"name": "Parent & Tot Swim",
"category": "swimming",
"age_min": 6,
"age_max": 12,
"cost_cents": 9000,
"adaptive": false,
"city": "calgary",
"url": "https://headsup.kids/calgary/programs/parent-tot-swim-b3f1c2a0",
"provider": { "name": "City of Calgary", "slug": "city-of-calgary" },
"neighbourhood": { "name": "Beltline", "slug": "beltline" },
"venue": { "name": "Repsol Sport Centre" }
}
],
"meta": { "total": 41, "next_cursor": "a1b2c3d4-5678-4e9f-a012-3456789abcde", "city": "calgary" }
}Unknown or uncovered city (404)
{
"error": {
"code": "unknown_city",
"message": "No published catalogue for \"seattle\"."
}
}Fetch a single program by id. Each registration carries opens_precision: on a "day" row the clock portion of registration_opens_at is a midnight placeholder and only the date is real.
Example request
/api/calgary/programs/b3f1c2a0-1234-4a5b-8c6d-9e0f1a2b3c4d
Example response
{
"data": {
"id": "b3f1c2a0-...",
"name": "Parent & Tot Swim",
"category": "swimming",
"age_min": 6,
"age_max": 12,
"cost_cents": 9000,
"adaptive": false,
"city": "calgary",
"url": "https://headsup.kids/calgary/programs/parent-tot-swim-b3f1c2a0",
"provider": { "name": "City of Calgary", "slug": null },
"neighbourhood": { "name": "Beltline", "slug": null },
"description": "A parent-participation intro to the water.",
"venue": {
"name": "Repsol Sport Centre",
"address": "2225 Macleod Trail S",
"neighbourhood": "Beltline",
"lat": 51.03,
"lng": -114.06
},
"sessions": [
{
"starts_on": "2026-09-08",
"ends_on": "2026-12-15",
"start_time": "16:00:00",
"end_time": "17:00:00"
}
],
"registrations": [
{
"season": "fall 2026",
"preview_opens_at": null,
"registration_opens_at": "2026-08-12T06:00:00Z",
"opens_precision": "day",
"registration_closes_at": null,
"confidence": "confirmed",
"audience": "public",
"source_url": "https://example.com/registration"
},
{
"season": "fall 2026",
"preview_opens_at": null,
"registration_opens_at": "2026-08-10T06:00:00Z",
"opens_precision": "day",
"registration_closes_at": null,
"confidence": "confirmed",
"audience": "member",
"source_url": "https://example.com/registration"
}
]
}
}Not found (404)
{
"error": {
"code": "not_found",
"message": "No program with that id."
}
}Upcoming registration-open dates for one city, soonest first. Read opens_precision before rendering a time: on a "day" row the clock portion of registration_opens_at is a midnight placeholder and only the date is real.
Query params
limitNumber of events to return. Default 200, max 500.
Example request
/api/calgary/calendar?limit=5
Example response
{
"data": [
{
"id": "c4a2d3b1-...",
"program_id": "b3f1c2a0-...",
"program_name": "Parent & Tot Swim",
"season": "Fall 2026",
"registration_opens_at": "2026-08-15T14:00:00.000Z",
"opens_precision": "minute",
"confidence": "confirmed",
"audience": "public",
"source_url": "https://www.calgary.ca/..."
}
],
"meta": { "city": "calgary" }
}The API is read-only and CORS-enabled. No authentication is required. There is no version segment: the shape below is the current and only contract, and a breaking change ships as a breaking change rather than behind a new prefix.