{"openapi":"3.1.0","info":{"title":"Tailend API","version":"1.0.0-draft","summary":"Read-only events, classes, camps, places and organizations for a multi-city family-activity product.","description":"Contract for the v1 public API. Nothing is invented at the edge: every\nfield is either read straight from the underlying data or computed by a\ndeterministic rule documented on that field.\n\n### Time\nEvents carry the place's **local wall-clock** time (`starts_local`,\n`ends_local`, `start_time`, `has_time`, `timezone`), computed at the\nplace's own IANA zone, plus the UTC instant (`starts_at`). Never add\nan offset to `starts_local`; it is already the time printed on the source\npage.\n\nNot every event has a date at all — a dateless recurring series (e.g. an\nall-day ride with no stated start) has `has_date: false` and both\n`starts_at`/`starts_local` are `null`, never an empty string. Check\n`has_date` before parsing either field. The default `from`/`to` window\nnever returns these rows, since it has nothing to compare against; a\ndateless event is only reachable by `id` or `slug`.\n\n**Timestamp convention:** a field named `*_at` is always UTC, RFC 3339,\ne.g. `2026-09-12T00:00:00Z` (`starts_at`, `ends_at`, `created_at`,\n`updated_at`, `crawled_at`, `next_at`, …). A field named `*_local` is a\nnaive local wall-clock timestamp with no offset (`starts_local`,\n`next_local`, …) — always read it against the object's own `timezone`. A\nfield named `*_on` is a calendar date with no time component (`starts_on`,\n`ends_on`, …). No field carries a `_utc` suffix; UTC is what `_at` means.\n\n### Paging\nThree ways to walk a collection, with different guarantees on purpose.\n**Browse** (`page`, or `cursor`) orders on the resource's natural key and\nis **best effort**: inserts and deletes are safe, but a row *edited*\nmid-traversal may be skipped or repeated, because the ordering fields are\nmutable. **Sync** (`changed_since` + `cursor`) orders on `updated_at`,\nwhich an edit can only move forward, and is therefore **at least once** —\na row may arrive twice, never zero times. `/v1/changes` pages on the\nmonotonic `version_id`, is **exactly once and in order**, and is the only\none that reports removals; it is the correct tool for keeping a mirror in\nstep. A **collection** cursor is opaque, bound to the request that issued\nit, and rejected with `400` anywhere else. The `/v1/changes` cursor is not\none of those: it is the last `version_id` you saw, in the clear, bound to\nnothing, and you are meant to store it. See\n[Pagination](/playground/guide/pagination).\n\n### Confidence and verification\nThe default payload is lean: every resource carries a flat `confidence`\n(0-1, exactly what `min_confidence` filters on) and `verified_at`\n(`null` until the listing has been verified), and nothing else on this\ntopic. Once a listing has been verified, `verified_at` reflects the last\ncheck; until then `confidence` is a documented **baseline**.\n\nWhere the data came from (`url`, `crawled_at`) and verification detail —\nwhether the score is `verified` or `baseline`, and the date/source health\nenums — are behind `include=source` (`Source` schema), a paid add-on\nentitled per key. Ask for it without the entitlement and get `403\ninclude_not_permitted`, or add `include_mode=lenient` for a `200`\nwithout the block plus a `notices[]` entry. See\n[Shaping responses](/playground/guide/shaping-responses).\n\n### Metros\nPaths are metro-scoped (`/v1/{metro}/events`). Metro slugs are reserved\nagainst the resource names (`events`, `classes`, `camps`, `places`,\n`organizations`, `changes`, `metros`) so the router is unambiguous.\n\n### Auth, scope and rate limits\nSend `X-API-Key`. A key is scoped to metros and resource types\n(`*` means all metros or all types) and has a\nper-minute limit. Every response carries `X-RateLimit-*` headers; a `429`\nalso carries `Retry-After`.\n\n### Quotas\nA client also has a **monthly request allowance** for its plan, counted\nacross all of its keys over a UTC calendar month. Where one applies, every\nresponse carries `X-Quota-Limit`, `X-Quota-Remaining` and `X-Quota-Reset`\n(unix seconds at the start of the next month); an unlimited plan sends none\nof them. See [Limits & usage](/playground/guide/limits-and-usage).\n\nBoth limits answer `429`, with **different `error.code` values**:\n`rate_limited` for the per-minute rate — wait out `Retry-After` and carry on\n— and `quota_exceeded` for a spent allowance or a hard cap, where\n`Retry-After` is the wait until the month rolls over and retrying sooner\ncannot succeed. Clients should switch on `error.code`, not on the status.\n\nRequests refused by either limit are not billed and do not consume the\nallowance they were refused by.\n\n### Headers\n`X-API-Key` (request); `ETag`/`If-None-Match`/`Cache-Control` (caching,\nbelow); `X-RateLimit-*`/`RateLimit-*`/`Retry-After`/`X-Quota-*` (limits,\nabove); `X-Request-Id`/`X-Trace-Id` on every response, for correlating a\nrequest with your logs and ours. Every header below is documented on the\nresponses that carry it.\n\n### Caching and conditional requests\nEvery successful response carries a weak `ETag`; a matching\n`If-None-Match` gets `304` with no body. `max-age` is 60s for\ncollections and spatial endpoints, 300s for detail reads, 3600s for\n`/v1/metros`, and `no-cache` for `/v1/changes`. A `304` is still a full\nread and is billable. See [Caching](/playground/guide/caching).\n\n### Shaping responses\n`fields=` trims a response to named dotted paths; `expand=place,organization`\nattaches the full object instead of just its reference; `include=source`\n(a paid add-on) attaches opt-in blocks. Diagnostic response fields are\navailable only to internal keys. An unentitled `include=` is `403\ninclude_not_permitted` unless `include_mode=lenient` is given, in which\ncase the response still succeeds with the block left off and a\n`notices[]` entry naming what was omitted.\n\n### Errors\nOne envelope everywhere: `{error: {code, message, details?,\nrequest_id}}`. Branch on `code`, never on `message` or on status alone\n— `403` and `429` each cover two codes with different remedies. See\n[Errors](/playground/guide/errors).\n\n### Versioning and stability\nThe version lives in the path only. v1 freezes at public launch: every\npath, parameter and response field named here becomes a promise: new\noptional parameters, new response fields and new `error.code` values may\nstill appear (parse permissively). `x-stability: beta`/`experimental` on\nan operation or parameter marks the exceptions to the freeze. See\n[Audience & versioning](/playground/guide/audience-and-versioning).\n\n### Audience and safety\nEvery event, class, camp and place carries an `audience` field (`kids`,\n`families`, `teens`, `adults`, `all_ages`), computed from a suitability\ncheck we run on each listing. **Adult-only content is excluded by\ndefault** on every list endpoint; pass `audience=all`, or name `adults`\nexplicitly, to include it. A detail read always returns the item\nregardless of audience. See\n[Audience & versioning](/playground/guide/audience-and-versioning).\n\n### Plans and access\nEvery operation, and each `include=` add-on, carries `x-access:\n{plan, credits}` (premium operations also carry `feature`; add-ons carry\n`addon`). The premium feature catalogue below is the badge source for the\nupcoming history, trends, and beta insights routes. Credits are\n`planned` — usage is metered by request volume today, not yet by\nrecord count. See [Plans & access](/playground/guide/plans-and-access).\n","contact":{"name":"Tailend API team","email":"support@tailend.dev"},"license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://api.tailend.dev","description":"Production. Also rendered at /docs."}],"security":[{"ApiKeyAuth":[]}],"x-access-addons":{"forecast":{"plan":"partner","addon":"forecast","credits":"+2 per record (planned)","description":"Included with partner; grantable per key on standard; unavailable on free."},"source":{"plan":"partner","addon":"source","credits":"+2 per record (planned)","description":"Included with partner; grantable per key on standard; unavailable on free."},"related":{"plan":"partner","addon":"related","credits":"none","description":"Included with partner; grantable per key on standard; unavailable on free. Single-listing reads only."}},"x-access-features":{"history":{"plan":"partner","feature":"history","description":"Included with partner; grantable per key on standard; unavailable on free."},"trends":{"plan":"partner","feature":"trends","description":"Included with partner; grantable per key on standard; unavailable on free."},"insights":{"plan":"partner","feature":"insights","stability":"beta","description":"Included with partner; grantable per key on standard; unavailable on free."}},"tags":[{"name":"Metros","description":"Cities the product serves."},{"name":"Search","description":"Unified discovery across listing collections."},{"name":"Events","description":"Single occurrences with a local start (and optional end) time."},{"name":"Classes","description":"Enrollable programs with a term, a weekly schedule and tuition."},{"name":"Camps","description":"Camps and their sessions (dated, priced blocks)."},{"name":"Places","description":"Places, with hours, admission, birthday and class facts."},{"name":"Organizations","description":"The organization behind a listing."},{"name":"Changes","description":"Versions feed for incremental sync."},{"name":"Directory","description":"Who publishes in a metro and where — organizations and neighborhoods with live counts."},{"name":"Coverage","description":"How much, how fresh, and how clean a metro's data is."},{"name":"Activity","description":"How lively a point is, computed from the listings near it."},{"name":"Address search","description":"Search around an address: one response with grouped, ranked results and an activity summary."}],"paths":{"/v1/metros":{"get":{"tags":["Metros"],"operationId":"listMetros","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List metros","description":"Active metros, with their slug, name, timezone and known aliases.","responses":{"200":{"description":"Metros","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Metro"}}}},"examples":{"default":{"summary":"Example response","value":{"data":[{"slug":"philadelphia","name":"Philadelphia Area","timezone":"America/New_York"}]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/search":{"get":{"tags":["Search"],"operationId":"searchListings","x-access":{"plan":"all","credits":"1 per request"},"summary":"Search every listing collection","description":"Searches published, active listings in one metro. When semantic search\nis enabled, results match by meaning as well as keywords.\nSearch applies the same visibility and filter rules as each list\nendpoint, so it never returns a listing that endpoint would hide.\nResults are ranked and paginated across collections.\nRecurring events use their next occurrence.\n\n**How words are matched.** The query is read as plain words: quotes,\na leading `-` and `OR` are not interpreted. Different forms of a word\nmatch each other (`swim` finds `swimming`), and a short list of closely\nrelated family-activity words also counts (`pottery` finds `ceramics`,\n`baking` finds `cooking`). Question and filler words (`where can I`,\n`with`, `for`, `the`) are ignored and never change a score. Words that\nonly name the kind of listing (`class`, `lessons`, `camp`) never decide\nwhether a listing matches; they only lift a listing that has them in its\nname.\n\n**Ages and audiences.** An age in the query becomes an age filter:\n`5 year olds`, `ages 3-5`, `toddlers` (1 to 3), `baby` (0 to 1) and\n`teens` (13 to 18). The band that was applied is echoed in\n`meta.interpreted.age`. When the query gives an age, listings whose stated\nages cover it rank above listings with no stated ages; listings whose ages\nexclude it are left out. An explicit `age` or `audience` parameter always\nwins: the age in the words is then not applied, and\n`meta.interpreted.age.overridden_by` says which parameter won. Time and\nprice words (`tonight`, `saturday`, `morning`, `cheap`) are not filters\nyet: they never decide a match and are listed in `meta.ignored_words`.\nAudience words\n(`parents`, `kids`, `family`) do not narrow the search when other words\nare present, and are listed in `meta.ignored_words`; a title that names\nthem still ranks a little higher. A query made only of such words is\nnever refused: `Mommy and Me`, `kids` and `family` search for those words\nas written. A query with nothing searchable at all (`near me`,\n`where can I`) returns `400`.\n\n**How directly a result matches.** Every result carries `match`.\n`all_terms`: every word you typed is in the listing's name or category,\nor is prominent in the opening of its description. `related`: every\nword is covered that way, but at least one only through a closely related\nword. `partial`: only some of your words, or all of them only mentioned\nin passing further down a description (`food` in a park concert that\nsells snacks). Inside a level, a name match ranks above a category match,\nwhich ranks above a description match. By default only `all_terms` and\n`related` are returned, so a count reflects real matches; send\n`match=all_terms,related,partial` (or `match=partial` alone) to include\nthe loose ones. `meta.match_counts` says how many results there are at\neach level, whatever `match` you chose, so a client can say \"17 direct,\n36 related, 1,378 loose\". Results are ordered so that `all_terms` come\nbefore `related`, and those before `partial`, unless you choose another\n`sort`.\n\n`score` is an absolute 0 to 1 measure of how well one listing fits the\nwords of the query. It is not scaled against the other results, so a\nweak best match no longer shows as 1, and the same listing gets the\nsame score whatever else is returned. It is not a probability. `snippet` is\na plain-text, unhighlighted excerpt of the listing's public description\n(or name when no description exists), at most 180 characters.\n\n`sort=relevance` is the default. `soonest` orders dated results by\ntheir next occurrence (including recurring events), with places and\nundated items after them. `nearest` orders by distance and requires\n`lat` + `lng` or `near_zip`. `newest` orders by `created_at`. Every\norder breaks ties by score, then id; cursors are bound to the sort and\nranking mode. If semantic availability changes between pages, the API\nreturns `400 bad_request` with `details.reason: cursor_expired`; restart\nthe search without a cursor so results are never silently skipped.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"name":"q","in":"query","required":true,"description":"Natural-language or keyword query, read as plain words. Filler, location and relative-date phrases are ignored; ages (`5 year olds`, `toddlers`) become an age filter (see `meta.interpreted`); audience words (`kids`) are listed in `meta.ignored_words`; different forms of a word and closely related words also match. Results can match by meaning as well as keywords.","schema":{"type":"string","minLength":1,"maxLength":200},"example":"toddler story time"},{"name":"types","in":"query","description":"Repeatable or comma-separated collections; defaults to all four.","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["events","classes","camps","places"]},"default":["events","classes","camps","places"]}},{"name":"sort","in":"query","description":"Cross-collection ordering. `nearest` requires `lat` + `lng` or `near_zip`.","schema":{"type":"string","enum":["relevance","soonest","nearest","newest"],"default":"relevance"},"examples":{"relevance":{"summary":"Best matches first","value":"relevance"},"soonest":{"summary":"Next dated occurrence first","value":"soonest"},"nearest":{"summary":"Closest to the supplied origin first","value":"nearest"},"newest":{"summary":"Most recently added first","value":"newest"}}},{"name":"match","in":"query","description":"Which match levels to return, as a comma-separated list of\n`all_terms`, `related` and `partial`. Defaults to `all_terms,related`;\n`partial` (loose matches) is returned only when you ask for it.\n`meta.match_counts` always counts every level.\n","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["all_terms","related","partial"]},"default":["all_terms","related"]},"examples":{"direct":{"summary":"Only direct matches","value":"all_terms"},"everything":{"summary":"Include loose matches","value":"all_terms,related,partial"}}},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/HasTime"},{"$ref":"#/components/parameters/Recurring"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Team"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Openings"},{"name":"schedule_day","in":"query","description":"Classes only; keep classes meeting on this weekday.","schema":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}},{"name":"enrollment_type","in":"query","description":"Classes only; filter by enrollment model.","schema":{"type":"string","enum":["drop_in","registration","membership","unknown"]}},{"name":"year","in":"query","description":"Camps only; program year.","schema":{"type":"integer","minimum":2020,"maximum":2100}},{"name":"overnight","in":"query","description":"Camps only; filter overnight programs.","schema":{"type":"boolean"}},{"name":"type_hint","in":"query","description":"Places only; filter by place type.","schema":{"type":"string"}},{"name":"has_birthday_parties","in":"query","description":"Places only; filter advertised birthday-party offerings.","schema":{"type":"boolean"}},{"name":"has_classes","in":"query","description":"Places only; filter places offering classes.","schema":{"type":"boolean"}},{"name":"indoor","in":"query","description":"Events and classes only; see the `indoor` parameter on the event list.","schema":{"type":"boolean"}},{"name":"outdoor","in":"query","description":"Events and classes only; see the `outdoor` parameter on the event list.","schema":{"type":"boolean"}},{"name":"sensory","in":"query","description":"Events, classes and places; see the `sensory` parameter on the event list.","schema":{"type":"boolean"}},{"name":"cursor","in":"query","description":"Opaque continuation token, bound to the query, types, filters, and sort.","schema":{"type":"string","maxLength":2000}},{"name":"limit","in":"query","description":"Results per page.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"A page spanning the selected collections in the requested sort order.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"},"examples":{"agentQuestion":{"summary":"Family activity search","value":{"data":[{"type":"event","id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","slug":"toddler-storytime","name":"Toddler Storytime","snippet":"Stories and songs for children ages 2–5.","match":"all_terms","score":0.92,"starts_local":"2026-10-03T10:00:00"}],"meta":{"query":"toddler story time","applied_filters":{"audience":["not_adults"],"by_type":{"events":{"from":"2026-09-28","to":"2026-10-28","min_confidence":0.7},"classes":{"from":"2026-09-28","to":null,"min_confidence":0.7},"camps":{"from":"2026-09-28","to":null,"min_confidence":0.7},"places":{"min_confidence":0.5}}},"defaults_applied":["from","to","min_confidence","audience"],"types":["events","classes","camps","places"],"ranking":"keyword","ignored_words":[],"interpreted":{"age":{"min":1,"max":3,"from":"toddlers"}},"match":["all_terms","related"],"match_counts":{"all_terms":1,"related":0,"partial":14},"sort":"relevance","limit":20,"count":1,"count_estimate":1,"capped":false,"has_more":false,"next_cursor":null,"generated_at":"2026-09-28T14:30:00Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/events":{"get":{"tags":["Events"],"operationId":"listEvents","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List events","description":"Published, active events in the metro, ordered by `starts_at` ascending\n(then `id`).\n\n`from`/`to` are **local dates** in the metro's timezone and compare against\n`starts_local`; `from` defaults to today, **`to` to `from` + 30 days**, so a\nlist with no `to` covers one month. Rows below `min_confidence` (**default\n`0.7`**) are dropped (pass `0` to disable), and `adults` audiences are left out\nunless asked for. `meta.applied_filters` echoes the value of each of these in\neffect and `meta.defaults_applied` lists the ones that came from a default.\n`facets=` adds counts over the whole filtered set; see\n[Market overview with facets](/playground/guide/market-overview-with-facets).\n`changed_since`\nswitches to sync mode: rows with `updated_at > changed_since`, ordered by\n`updated_at, id`, paged with `cursor` instead of `page`.\n\n`occurrences=expand` lists every occurrence of a recurring event in the\nwindow, for calendar views; see the `occurrences` parameter. For per-day\ncounts over a month, see `/v1/{metro}/events/calendar`.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/Ids"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Team"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/HasTime"},{"$ref":"#/components/parameters/Recurring"},{"$ref":"#/components/parameters/Occurrences"},{"$ref":"#/components/parameters/Indoor"},{"$ref":"#/components/parameters/Outdoor"},{"$ref":"#/components/parameters/Sensory"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of events. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":"2026-10-14","min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","to","min_confidence","audience"]}}},"market_overview":{"summary":"Facets only (`facets=...&limit=0`)","description":"Sizes a market without paging it. `data` is empty; every count covers the whole filtered set.","value":{"data":[],"facets":{"total":412,"is_complete":true,"category":[{"value":"arts_creative","count":131},{"value":"sports_active_play","count":96},{"value":"storytime_books","count":74},{"value":"unspecified","count":9}],"weekday":[{"value":"monday","count":41},{"value":"tuesday","count":55},{"value":"wednesday","count":58},{"value":"thursday","count":60},{"value":"friday","count":52},{"value":"saturday","count":84},{"value":"sunday","count":62}],"time_block":[{"value":"morning","count":203},{"value":"afternoon","count":131},{"value":"evening","count":62},{"value":"unspecified","count":16}],"price_band":[{"value":"free","count":188},{"value":"under_20","count":91},{"value":"20_to_50","count":54},{"value":"50_to_100","count":22},{"value":"100_plus","count":6},{"value":"unspecified","count":51}],"age_band":[{"value":"baby","count":97},{"value":"toddler","count":160},{"value":"young_kids","count":204},{"value":"bigger_kids","count":141},{"value":"unspecified","count":38}],"organization":{"distinct":57,"top":[{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Free Library of Philadelphia","count":88},{"id":"7d0e8a52-3c1b-4f6e-9a2d-5b8c1e4f7a90","name":"Please Touch Museum","count":31}],"other_count":290,"unspecified_count":3}},"meta":{"metro":"philadelphia","page":1,"limit":0,"count":0,"has_more":false,"next_cursor":null,"min_confidence":0.7,"window":{"from":"2026-09-14","to":"2026-10-14","timezone":"America/New_York"},"applied_filters":{"from":"2026-09-14","to":"2026-10-14","min_confidence":0.7,"audience":["not_adults"],"lat":39.9526,"lng":-75.1652,"radius_m":8000},"defaults_applied":["from","to","min_confidence","audience"],"generated_at":"2026-09-14T12:00:00.000Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/events/calendar":{"get":{"tags":["Events"],"operationId":"getEventCalendar","x-access":{"plan":"all","credits":"1 per request (planned)"},"summary":"Event counts per day","description":"For each local date in `[from, to]` (both required, at most 62 days\ninclusive), how many event occurrences start that day, how many of them\nare free, and how many fall in each category — every date included,\nwith zeros. Occurrences are exactly the ones `/v1/{metro}/events` lists\nwith `occurrences=expand` under the same filters, so a month view's\ncounts always agree with the week or day list behind them.\n\nTakes the same filters as `/events`. `weekday`, `start_after`,\n`start_before` and `season` apply to each occurrence. `cursor`, `page`,\n`fields`, `expand`, `changed_since`, `q` and `facets` are not available.\n\n`include=forecast` (a paid add-on, entitled as on `/events`) adds a\n`forecast` to today and each of the next seven days.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"name":"from","in":"query","required":true,"description":"First local date of the window, `YYYY-MM-DD`.","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":true,"description":"Last local date of the window (inclusive), at most 61 days after `from`.","schema":{"type":"string","format":"date"}},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Team"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/HasTime"},{"$ref":"#/components/parameters/Recurring"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"One entry per date in the window.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventCalendar"},"examples":{"default":{"summary":"Example response","value":{"data":[{"date":"2026-10-05","count":41,"free_count":22,"categories":{"storytime_books":14,"arts_creative":9,"sports_active_play":6}},{"date":"2026-10-06","count":0,"free_count":0,"categories":{}},{"date":"2026-10-07","count":57,"free_count":31,"categories":{"storytime_books":19,"music_movement":8},"forecast":{"summary":"Chance Showers","temperature_f":{"min":54,"max":66},"precipitation_chance_max":60,"wet_hours":[[13,16]],"issued_at":"2026-10-05T14:00:00Z","expires_at":"2026-10-05T15:00:00Z"}}],"meta":{"metro":"philadelphia","window":{"from":"2026-10-05","to":"2026-10-07","timezone":"America/New_York"},"min_confidence":0.7,"total":98,"applied_filters":{"from":"2026-10-05","to":"2026-10-07","min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["min_confidence","audience"],"generated_at":"2026-10-07T12:00:00.000Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/events/{id}":{"get":{"tags":["Events"],"operationId":"getEvent","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve an event","description":"An event by id. Published and active by default; archived rows\nanswer `404` unless `include_archived=true`, and drafts never appear.\nThe response carries `status`, so a permalink can render a past\nlisting with a banner instead of a dead link. Removals are also\nvisible on `/v1/changes`.\n","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The event","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"}}}},"with_source":{"summary":"Example response — include=source","value":{"data":{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"},"source":{"url":"https://treehouseworld.com/pages/admission-prices","crawled_at":"2026-09-14T08:04:04.458Z","verification":{"status":"clear","basis":"verified","date_basis":"stated"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/events/slug/{slug}":{"get":{"tags":["Events"],"operationId":"getEventBySlug","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve an event by slug","description":"Returns the same event as `/v1/events/{id}`, addressed by slug instead of id.\n\n`slug` is unique per (metro, type). If the key can see this slug in more\nthan one metro, returns `400` with `details.metros`; pass `metro=` to\ndisambiguate. `include_archived=true` returns an archived row.\n\nReturns 503 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/SlugPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The event","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/classes":{"get":{"tags":["Classes"],"operationId":"listClasses","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List classes","description":"Published, active classes. `from`/`to` select terms that **overlap** the window\n(`term.starts_on <= to AND (term.ends_on IS NULL OR term.ends_on >= from)`);\nongoing programs (`schedule.type = 'ongoing'`) and terms with no dates\nalways match. Unlike events, `to` has no default here: with `from` alone\n(default today) the window is open-ended, so next season's terms are\nlisted. Rows below `min_confidence` (**default `0.7`**) and `adults`\naudiences are left out unless asked for; `meta.applied_filters` and\n`meta.defaults_applied` echo what was applied. `facets=` adds counts over\nthe whole filtered set. Ordered by `term.starts_on` nulls last, then `name`.\n\n**Sections.** A program with `sections` is matched by one section at a time: the weekday\n(`schedule_day`, `weekday`), `age`, `start_after`/`start_before`, the dates and `season`,\n`free`/`max_price` and `openings=true` must all be satisfied by the same section. A Saturday\nsection for ages 3-5 and a Sunday section for ages 9-12 do not match `schedule_day=saturday&age=10`.\nA program with no sections is judged on its own fields. Filters decide which programs are\nreturned; they never trim a program's `sections`.\n\n**Grouping.** When a provider publishes one program as several listings, the list shows a\nsingle card for it, with the other listings under `sessions`. Cards are formed before\npaging, so a page never splits one and `limit` counts cards. `expand=sessions` returns every\nclass on its own.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/Ids"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/StartsFrom"},{"$ref":"#/components/parameters/StartsTo"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/Openings"},{"$ref":"#/components/parameters/Indoor"},{"$ref":"#/components/parameters/Outdoor"},{"$ref":"#/components/parameters/Sensory"},{"name":"schedule_day","in":"query","description":"Keep classes that meet on this weekday.","schema":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}},{"name":"enrollment_type","in":"query","description":"Keep rows matching this enrollment type.","schema":{"type":"string","enum":["enrollment","unknown"]}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of classes. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"c57d9bae-6479-41c5-9176-f314fa4d31f4","type":"class","slug":"kids-pottery-classes-b3d835f7","name":"Kids Pottery Classes","description":"6-week pottery classes for kids ages 8-16, focusing on wheel-throwing and hand-building techniques.","program":{"enrollment_type":"enrollment","skill_level_notes":"all levels","adult_participation":null,"what_youll_learn":null,"prerequisites":null},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"schedule":{"type":"session","days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"tuition":{"amount":185,"from":185,"text":"$185 for 6-week session","drop_in_price":null,"trial_price":null,"trial_notes":null,"currency":"USD"},"price":{"type":"fixed","min":185,"max":185,"scope":"admission","note":"$185 for 6-week session","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":8,"max":16,"text":"Early Elementary, Tweens, Teens","audience":"kids","bands":["bigger_kids"]},"audience":"teens","traits":{"seasons":["fall","winter"]},"place":{"id":"1af0824d-36cf-482d-a6d7-073343ae52ed","slug":"earth-center-pottery-ebc6fdd7","name":"Earth Center Pottery"},"location":{"address":"10 Stable Mill Trl, Richboro, PA 18954, USA","street_address":"10 Stable Mill Trl, Richboro, PA 18954, USA","city":"Richboro","state":"PA","zip":"18954","lat":40.2226282,"lng":-74.9866812,"neighborhood":"Somerton","neighborhood_slug":"somerton"},"categories":["arts_creative"],"occasions":[],"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","opens_at":null,"spots_remaining":null,"has_spots_available":true,"waitlist_available":false,"sections_with_spots":1},"sections_total":1,"sections":[{"id":"0b8a3f5e-52c4-4d64-9a0e-2f6d7c1e9a11","name":"Tuesday afternoon","schedule":{"days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"ages":{"min":8,"max":16,"text":null},"tuition":{"amount":185,"text":"$185 for 6-week session","drop_in_price":null,"currency":"USD"},"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","spots_remaining":null,"has_spots_available":true,"waitlist_available":false},"updated_at":"2026-09-26T12:01:08.782Z"}],"sessions":[],"image_url":"https://earthcenterpottery.com/wp-content/uploads/2024/02/IMG_0318-scaled-e1707359564209-1024x566.jpg","organization":{"id":"37bae48b-e86c-44a4-80d7-29fd9c34443c","name":"Earth Center Pottery","slug":"earthcenterpotterycom-f09a2fcc"},"confidence":0.45,"verified_at":"2026-09-26T12:00:21.748Z","metro":"philadelphia","status":"published","created_at":"2026-07-17T16:01:41.805Z","updated_at":"2026-09-26T12:01:08.782Z","links":{"self":"/v1/classes/c57d9bae-6479-41c5-9176-f314fa4d31f4","place":"/v1/places/1af0824d-36cf-482d-a6d7-073343ae52ed","organization":"/v1/organizations/37bae48b-e86c-44a4-80d7-29fd9c34443c"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/classes/{id}":{"get":{"tags":["Classes"],"operationId":"getClass","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a class","description":"A class by id. Published and active by default; archived rows answer\n`404` unless `include_archived=true`, and drafts never appear. The\nresponse carries `status`.\n","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The class","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Class"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"c57d9bae-6479-41c5-9176-f314fa4d31f4","type":"class","slug":"kids-pottery-classes-b3d835f7","name":"Kids Pottery Classes","description":"6-week pottery classes for kids ages 8-16, focusing on wheel-throwing and hand-building techniques.","program":{"enrollment_type":"enrollment","skill_level_notes":"all levels","adult_participation":null,"what_youll_learn":null,"prerequisites":null},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"schedule":{"type":"session","days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"tuition":{"amount":185,"from":185,"text":"$185 for 6-week session","drop_in_price":null,"trial_price":null,"trial_notes":null,"currency":"USD"},"price":{"type":"fixed","min":185,"max":185,"scope":"admission","note":"$185 for 6-week session","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":8,"max":16,"text":"Early Elementary, Tweens, Teens","audience":"kids","bands":["bigger_kids"]},"audience":"teens","traits":{"seasons":["fall","winter"]},"place":{"id":"1af0824d-36cf-482d-a6d7-073343ae52ed","slug":"earth-center-pottery-ebc6fdd7","name":"Earth Center Pottery"},"location":{"address":"10 Stable Mill Trl, Richboro, PA 18954, USA","street_address":"10 Stable Mill Trl, Richboro, PA 18954, USA","city":"Richboro","state":"PA","zip":"18954","lat":40.2226282,"lng":-74.9866812,"neighborhood":"Somerton","neighborhood_slug":"somerton"},"categories":["arts_creative"],"occasions":[],"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","opens_at":null,"spots_remaining":null,"has_spots_available":true,"waitlist_available":false,"sections_with_spots":1},"sections_total":1,"sections":[{"id":"0b8a3f5e-52c4-4d64-9a0e-2f6d7c1e9a11","name":"Tuesday afternoon","schedule":{"days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"ages":{"min":8,"max":16,"text":null},"tuition":{"amount":185,"text":"$185 for 6-week session","drop_in_price":null,"currency":"USD"},"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","spots_remaining":null,"has_spots_available":true,"waitlist_available":false},"updated_at":"2026-09-26T12:01:08.782Z"}],"sessions":[],"image_url":"https://earthcenterpottery.com/wp-content/uploads/2024/02/IMG_0318-scaled-e1707359564209-1024x566.jpg","organization":{"id":"37bae48b-e86c-44a4-80d7-29fd9c34443c","name":"Earth Center Pottery","slug":"earthcenterpotterycom-f09a2fcc"},"confidence":0.45,"verified_at":"2026-09-26T12:00:21.748Z","metro":"philadelphia","status":"published","created_at":"2026-07-17T16:01:41.805Z","updated_at":"2026-09-26T12:01:08.782Z","links":{"self":"/v1/classes/c57d9bae-6479-41c5-9176-f314fa4d31f4","place":"/v1/places/1af0824d-36cf-482d-a6d7-073343ae52ed","organization":"/v1/organizations/37bae48b-e86c-44a4-80d7-29fd9c34443c"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/classes/slug/{slug}":{"get":{"tags":["Classes"],"operationId":"getClassBySlug","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a class by slug","description":"Returns the same class as `/v1/classes/{id}`, addressed by slug instead of id.\n\n`slug` is unique per (metro, type). If the key can see this slug in more\nthan one metro, returns `400` with `details.metros`; pass `metro=` to\ndisambiguate. `include_archived=true` returns an archived row.\n\nReturns 503 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/SlugPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The class","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Class"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"c57d9bae-6479-41c5-9176-f314fa4d31f4","type":"class","slug":"kids-pottery-classes-b3d835f7","name":"Kids Pottery Classes","description":"6-week pottery classes for kids ages 8-16, focusing on wheel-throwing and hand-building techniques.","program":{"enrollment_type":"enrollment","skill_level_notes":"all levels","adult_participation":null,"what_youll_learn":null,"prerequisites":null},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"schedule":{"type":"session","days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"tuition":{"amount":185,"from":185,"text":"$185 for 6-week session","drop_in_price":null,"trial_price":null,"trial_notes":null,"currency":"USD"},"price":{"type":"fixed","min":185,"max":185,"scope":"admission","note":"$185 for 6-week session","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":8,"max":16,"text":"Early Elementary, Tweens, Teens","audience":"kids","bands":["bigger_kids"]},"audience":"teens","traits":{"seasons":["fall","winter"]},"place":{"id":"1af0824d-36cf-482d-a6d7-073343ae52ed","slug":"earth-center-pottery-ebc6fdd7","name":"Earth Center Pottery"},"location":{"address":"10 Stable Mill Trl, Richboro, PA 18954, USA","street_address":"10 Stable Mill Trl, Richboro, PA 18954, USA","city":"Richboro","state":"PA","zip":"18954","lat":40.2226282,"lng":-74.9866812,"neighborhood":"Somerton","neighborhood_slug":"somerton"},"categories":["arts_creative"],"occasions":[],"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","opens_at":null,"spots_remaining":null,"has_spots_available":true,"waitlist_available":false,"sections_with_spots":1},"sections_total":1,"sections":[{"id":"0b8a3f5e-52c4-4d64-9a0e-2f6d7c1e9a11","name":"Tuesday afternoon","schedule":{"days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"ages":{"min":8,"max":16,"text":null},"tuition":{"amount":185,"text":"$185 for 6-week session","drop_in_price":null,"currency":"USD"},"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","spots_remaining":null,"has_spots_available":true,"waitlist_available":false},"updated_at":"2026-09-26T12:01:08.782Z"}],"sessions":[],"image_url":"https://earthcenterpottery.com/wp-content/uploads/2024/02/IMG_0318-scaled-e1707359564209-1024x566.jpg","organization":{"id":"37bae48b-e86c-44a4-80d7-29fd9c34443c","name":"Earth Center Pottery","slug":"earthcenterpotterycom-f09a2fcc"},"confidence":0.45,"verified_at":"2026-09-26T12:00:21.748Z","metro":"philadelphia","status":"published","created_at":"2026-07-17T16:01:41.805Z","updated_at":"2026-09-26T12:01:08.782Z","links":{"self":"/v1/classes/c57d9bae-6479-41c5-9176-f314fa4d31f4","place":"/v1/places/1af0824d-36cf-482d-a6d7-073343ae52ed","organization":"/v1/organizations/37bae48b-e86c-44a4-80d7-29fd9c34443c"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/camps":{"get":{"tags":["Camps"],"operationId":"listCamps","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List camps","description":"Published, active camps, with their sessions. `from`/`to` select camps whose\noverall span (`starts_on`..`ends_on`) or any session overlaps the window;\nundated camps always match. As for classes, `to` has no default: `from`\nalone (default today) is open-ended. Rows below `min_confidence` (**default\n`0.7`**) and `adults` audiences are left out unless asked for;\n`meta.applied_filters` and `meta.defaults_applied` echo what was applied.\n`facets=` adds counts over the whole filtered set. Ordered by `starts_on`\nnulls last, then `name`.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/Ids"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"name":"year","in":"query","description":"The camp's year.","schema":{"type":"integer","minimum":2020,"maximum":2100}},{"name":"overnight","in":"query","description":"Keep only overnight camps.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of camps. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","type":"camp","slug":"2026-summer-circus-camp-e49f4a3a","name":"2026 Summer Circus Camp","description":"The Philadelphia School of Circus Arts – Best of Philly Winner for “Kids Classes” – announces Summer Circus Camp 2026 for youth ages 4 – 15. Circus Camp returns with our 1-week camp program designed for campers with an emphasis on play and exploration in the exciting world of circus. Campers will learn static trapeze, aerial sling, aerial fabric, wire walking, juggling, plate-spinning, rolling globe, tumbling, unicycling, clowning and more. We can’t wait to share the excitement and challenge of the circus with kids in our full-day program!","season":"summer","year":2026,"starts_on":"2026-06-01","ends_on":"2026-06-05","schedule":{"type":null,"is_full_day":true,"is_half_day_am":false,"is_half_day_pm":false,"day_start_time":"09:00:00","day_end_time":"15:00:00","extended_care":{"morning_start":null,"morning_price":null,"afternoon_end":null,"afternoon_price":null,"notes":"Before Care: $20/day; After Care: $35/day","currency":"USD"},"timezone":"America/New_York"},"is_overnight":false,"is_travel":false,"is_specialty":false,"pricing_unit":"per_week","price":{"type":"fixed","min":495,"max":495,"scope":"admission","note":"$495/week","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":4,"max":15,"text":null,"audience":null,"bands":["young_kids","bigger_kids"]},"audience":"teens","traits":{"seasons":["summer"]},"place":{"id":"1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","slug":"philadelphia-school-of-circus-arts-62377244","name":"Philadelphia School of Circus Arts"},"location":{"address":"6452 Greene Street","street_address":"6452 Greene Street","city":"Philadelphia","state":"PA","zip":"19119","lat":40.0419162,"lng":-75.1896032,"neighborhood":"Northwest Philadelphia","neighborhood_slug":null},"categories":["sports_active_play"],"registration":{"url":"https://portal.iclasspro.com/phillycircus/booking","opens_on":null,"deadline_on":null,"early_bird_deadline_on":null,"has_spots_available":true,"sessions_with_spots":1},"sessions":[{"id":"4fbe88ce-c939-450e-92a0-e92c3f04ed6c","name":"Summer Circus Camp 2026","starts_on":"2026-06-01","ends_on":"2026-06-05","price":495,"early_bird_price":null,"full_day_price":null,"half_day_price":null,"currency":"USD","capacity":null,"spots_remaining":null,"status":"open","theme":null,"notes":null}],"image_url":"https://phillycircus.com/wp-content/uploads/PSCA-web-promo-01.jpg","organization":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts"},"confidence":0.55,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-09-22T06:11:27.636Z","updated_at":"2026-09-26T08:19:23.038Z","links":{"self":"/v1/camps/7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","place":"/v1/places/1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","organization":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/camps/{id}":{"get":{"tags":["Camps"],"operationId":"getCamp","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a camp","description":"A camp by id. Published and active by default; archived rows answer\n`404` unless `include_archived=true`, and drafts never appear. The\nresponse carries `status`.\n","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The camp","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Camp"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","type":"camp","slug":"2026-summer-circus-camp-e49f4a3a","name":"2026 Summer Circus Camp","description":"The Philadelphia School of Circus Arts – Best of Philly Winner for “Kids Classes” – announces Summer Circus Camp 2026 for youth ages 4 – 15. Circus Camp returns with our 1-week camp program designed for campers with an emphasis on play and exploration in the exciting world of circus. Campers will learn static trapeze, aerial sling, aerial fabric, wire walking, juggling, plate-spinning, rolling globe, tumbling, unicycling, clowning and more. We can’t wait to share the excitement and challenge of the circus with kids in our full-day program!","season":"summer","year":2026,"starts_on":"2026-06-01","ends_on":"2026-06-05","schedule":{"type":null,"is_full_day":true,"is_half_day_am":false,"is_half_day_pm":false,"day_start_time":"09:00:00","day_end_time":"15:00:00","extended_care":{"morning_start":null,"morning_price":null,"afternoon_end":null,"afternoon_price":null,"notes":"Before Care: $20/day; After Care: $35/day","currency":"USD"},"timezone":"America/New_York"},"is_overnight":false,"is_travel":false,"is_specialty":false,"pricing_unit":"per_week","price":{"type":"fixed","min":495,"max":495,"scope":"admission","note":"$495/week","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":4,"max":15,"text":null,"audience":null,"bands":["young_kids","bigger_kids"]},"audience":"teens","traits":{"seasons":["summer"]},"place":{"id":"1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","slug":"philadelphia-school-of-circus-arts-62377244","name":"Philadelphia School of Circus Arts"},"location":{"address":"6452 Greene Street","street_address":"6452 Greene Street","city":"Philadelphia","state":"PA","zip":"19119","lat":40.0419162,"lng":-75.1896032,"neighborhood":"Northwest Philadelphia","neighborhood_slug":null},"categories":["sports_active_play"],"registration":{"url":"https://portal.iclasspro.com/phillycircus/booking","opens_on":null,"deadline_on":null,"early_bird_deadline_on":null,"has_spots_available":true,"sessions_with_spots":1},"sessions":[{"id":"4fbe88ce-c939-450e-92a0-e92c3f04ed6c","name":"Summer Circus Camp 2026","starts_on":"2026-06-01","ends_on":"2026-06-05","price":495,"early_bird_price":null,"full_day_price":null,"half_day_price":null,"currency":"USD","capacity":null,"spots_remaining":null,"status":"open","theme":null,"notes":null}],"image_url":"https://phillycircus.com/wp-content/uploads/PSCA-web-promo-01.jpg","organization":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts"},"confidence":0.55,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-09-22T06:11:27.636Z","updated_at":"2026-09-26T08:19:23.038Z","links":{"self":"/v1/camps/7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","place":"/v1/places/1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","organization":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/camps/slug/{slug}":{"get":{"tags":["Camps"],"operationId":"getCampBySlug","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a camp by slug","description":"Returns the same camp as `/v1/camps/{id}`, addressed by slug instead of id.\n\n`slug` is unique per (metro, type). If the key can see this slug in more\nthan one metro, returns `400` with `details.metros`; pass `metro=` to\ndisambiguate. `include_archived=true` returns an archived row.\n\nReturns 503 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/SlugPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The camp","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Camp"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","type":"camp","slug":"2026-summer-circus-camp-e49f4a3a","name":"2026 Summer Circus Camp","description":"The Philadelphia School of Circus Arts – Best of Philly Winner for “Kids Classes” – announces Summer Circus Camp 2026 for youth ages 4 – 15. Circus Camp returns with our 1-week camp program designed for campers with an emphasis on play and exploration in the exciting world of circus. Campers will learn static trapeze, aerial sling, aerial fabric, wire walking, juggling, plate-spinning, rolling globe, tumbling, unicycling, clowning and more. We can’t wait to share the excitement and challenge of the circus with kids in our full-day program!","season":"summer","year":2026,"starts_on":"2026-06-01","ends_on":"2026-06-05","schedule":{"type":null,"is_full_day":true,"is_half_day_am":false,"is_half_day_pm":false,"day_start_time":"09:00:00","day_end_time":"15:00:00","extended_care":{"morning_start":null,"morning_price":null,"afternoon_end":null,"afternoon_price":null,"notes":"Before Care: $20/day; After Care: $35/day","currency":"USD"},"timezone":"America/New_York"},"is_overnight":false,"is_travel":false,"is_specialty":false,"pricing_unit":"per_week","price":{"type":"fixed","min":495,"max":495,"scope":"admission","note":"$495/week","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":4,"max":15,"text":null,"audience":null,"bands":["young_kids","bigger_kids"]},"audience":"teens","traits":{"seasons":["summer"]},"place":{"id":"1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","slug":"philadelphia-school-of-circus-arts-62377244","name":"Philadelphia School of Circus Arts"},"location":{"address":"6452 Greene Street","street_address":"6452 Greene Street","city":"Philadelphia","state":"PA","zip":"19119","lat":40.0419162,"lng":-75.1896032,"neighborhood":"Northwest Philadelphia","neighborhood_slug":null},"categories":["sports_active_play"],"registration":{"url":"https://portal.iclasspro.com/phillycircus/booking","opens_on":null,"deadline_on":null,"early_bird_deadline_on":null,"has_spots_available":true,"sessions_with_spots":1},"sessions":[{"id":"4fbe88ce-c939-450e-92a0-e92c3f04ed6c","name":"Summer Circus Camp 2026","starts_on":"2026-06-01","ends_on":"2026-06-05","price":495,"early_bird_price":null,"full_day_price":null,"half_day_price":null,"currency":"USD","capacity":null,"spots_remaining":null,"status":"open","theme":null,"notes":null}],"image_url":"https://phillycircus.com/wp-content/uploads/PSCA-web-promo-01.jpg","organization":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts"},"confidence":0.55,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-09-22T06:11:27.636Z","updated_at":"2026-09-26T08:19:23.038Z","links":{"self":"/v1/camps/7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","place":"/v1/places/1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","organization":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/places":{"get":{"tags":["Places"],"operationId":"listPlaces","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List places","description":"Published, active places, ordered by `name`. `min_confidence` defaults to **0.5** (events, classes and camps default to `0.7`), and `adults` audiences are left out unless asked for; `meta.applied_filters` and `meta.defaults_applied` echo what was applied. `facets=` adds counts over the whole filtered set. `type_hint=`/`place_type=` are the same filter under two spellings; `place_type=` is the deprecated one.","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/Ids"},{"$ref":"#/components/parameters/PlaceMinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"name":"type_hint","in":"query","description":"Filters on the place's type (see `Place.type_hint`).","schema":{"$ref":"#/components/schemas/PlaceTypeHint"}},{"name":"place_type","in":"query","deprecated":true,"description":"The deprecated spelling of `type_hint`. Still read; `type_hint` wins when both are given.","schema":{"$ref":"#/components/schemas/PlaceTypeHint"}},{"name":"has_birthday_parties","in":"query","schema":{"type":"boolean"}},{"name":"has_classes","in":"query","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Sensory"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of places. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","type":"place","slug":"philly-art-center-queen-village","name":"Philly Art Center - Queen Village","description":"Philly Art Center's Queen Village studio offers classes, camps, and after-school programs for kids from infancy through tweens, plus adult classes in drawing, painting, printmaking, fibers, and clay. Programs include Creative Playgroup + Story Time (drop-in for 0-30 months), adult+child music and art classes, drop-off kids art classes (ages 2+), tween classes, summer camps (ages 4-13), vacation camps (ages 5-12), and after-school art with free school pick-up. Process over product philosophy — all materials included.","type_hint":"other","type_hint_notes":"Art studio / creative learning center","location":{"address":"514 Bainbridge St, Philadelphia, PA 19147, USA","street_address":"514 Bainbridge St, Philadelphia, PA 19147, USA","city":"Philadelphia","state":"PA","zip":"19147","lat":39.9408481,"lng":-75.1516337,"neighborhood":"Queen Village","neighborhood_slug":"queen-village"},"hours":{"monday":"Closed","tuesday":"Class hours vary","wednesday":"Class hours vary","thursday":"Class hours vary","friday":"Class hours vary","saturday":"Class hours vary","sunday":"Closed","notes":"Hours vary by class schedule. Check phillyartcenter.captyn.com for current session times.","exceptions":null},"admission":{"type":"paid","child_price":null,"adult_price":null,"infant_age_cutoff":null,"notes":"Varies by program. Tuition assistance available. 10% household discount.","currency":"USD"},"membership":{"available":false,"price_monthly":null,"price_annual":null,"notes":null,"currency":"USD"},"birthday_parties":{"available":false,"min_guests":null,"max_guests":null,"age_range":null,"booking_url":null,"notes":null},"classes":{"available":true,"types":["art","music","playgroup","after school art"],"age_range":"0-12 years","schedule_notes":"Fall Registration is LIVE!","registration_url":"https://phillyartcenter.com/kids-classes/"},"amenities":{"has_outdoor_space":false,"has_parking":false,"parking_notes":"Street parking on Bainbridge St and surrounding blocks.","has_wifi":false,"socks_required":false,"outside_food_allowed":true,"stroller_policy":null},"ages":{"min":0,"max":17,"text":"Playgroup: 0-30 months. Adult+child classes: 3-36 months. Kids classes: ages 2+. Tween classes available. Summer camps: 4-13. Vacation camps: 5-12.","audience":null,"bands":["baby","toddler","young_kids","bigger_kids"]},"audience":"teens","categories":["arts_creative"],"image_url":"https://a.mpcdn.io/pac/2023/04/pac-social-share.jpg?auto=compress%2Cformat&ixlib=php-3.3.1","images":["https://mpcdn.imgix.net/pac/26/04/web-banner_fnl-copy-2.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://mpcdn.imgix.net/pac/26/07/fall-classes_final-1.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://a.mpcdn.io/pac/2023/03/testimonial-bg.jpg?auto=compress%2Cformat&ixlib=php-3.3.1"],"website_url":"https://phillyartcenter.com/","organization":{"id":null,"name":null,"slug":null},"confidence":0.7,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-02-18T19:16:17.504Z","updated_at":"2026-09-21T18:07:17.391Z","links":{"self":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","events":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/events","classes":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/classes","camps":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/camps"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"min_confidence":0.5,"audience":["not_adults"]},"defaults_applied":["min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/places/{id}":{"get":{"tags":["Places"],"operationId":"getPlace","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a place","description":"A place by id. Published and active by default; archived rows answer\n`404` unless `include_archived=true`, and drafts never appear. The\nresponse carries `status`.\n","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The place","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Place"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","type":"place","slug":"philly-art-center-queen-village","name":"Philly Art Center - Queen Village","description":"Philly Art Center's Queen Village studio offers classes, camps, and after-school programs for kids from infancy through tweens, plus adult classes in drawing, painting, printmaking, fibers, and clay. Programs include Creative Playgroup + Story Time (drop-in for 0-30 months), adult+child music and art classes, drop-off kids art classes (ages 2+), tween classes, summer camps (ages 4-13), vacation camps (ages 5-12), and after-school art with free school pick-up. Process over product philosophy — all materials included.","type_hint":"other","type_hint_notes":"Art studio / creative learning center","location":{"address":"514 Bainbridge St, Philadelphia, PA 19147, USA","street_address":"514 Bainbridge St, Philadelphia, PA 19147, USA","city":"Philadelphia","state":"PA","zip":"19147","lat":39.9408481,"lng":-75.1516337,"neighborhood":"Queen Village","neighborhood_slug":"queen-village"},"hours":{"monday":"Closed","tuesday":"Class hours vary","wednesday":"Class hours vary","thursday":"Class hours vary","friday":"Class hours vary","saturday":"Class hours vary","sunday":"Closed","notes":"Hours vary by class schedule. Check phillyartcenter.captyn.com for current session times.","exceptions":null},"admission":{"type":"paid","child_price":null,"adult_price":null,"infant_age_cutoff":null,"notes":"Varies by program. Tuition assistance available. 10% household discount.","currency":"USD"},"membership":{"available":false,"price_monthly":null,"price_annual":null,"notes":null,"currency":"USD"},"birthday_parties":{"available":false,"min_guests":null,"max_guests":null,"age_range":null,"booking_url":null,"notes":null},"classes":{"available":true,"types":["art","music","playgroup","after school art"],"age_range":"0-12 years","schedule_notes":"Fall Registration is LIVE!","registration_url":"https://phillyartcenter.com/kids-classes/"},"amenities":{"has_outdoor_space":false,"has_parking":false,"parking_notes":"Street parking on Bainbridge St and surrounding blocks.","has_wifi":false,"socks_required":false,"outside_food_allowed":true,"stroller_policy":null},"ages":{"min":0,"max":17,"text":"Playgroup: 0-30 months. Adult+child classes: 3-36 months. Kids classes: ages 2+. Tween classes available. Summer camps: 4-13. Vacation camps: 5-12.","audience":null,"bands":["baby","toddler","young_kids","bigger_kids"]},"audience":"teens","categories":["arts_creative"],"image_url":"https://a.mpcdn.io/pac/2023/04/pac-social-share.jpg?auto=compress%2Cformat&ixlib=php-3.3.1","images":["https://mpcdn.imgix.net/pac/26/04/web-banner_fnl-copy-2.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://mpcdn.imgix.net/pac/26/07/fall-classes_final-1.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://a.mpcdn.io/pac/2023/03/testimonial-bg.jpg?auto=compress%2Cformat&ixlib=php-3.3.1"],"website_url":"https://phillyartcenter.com/","organization":{"id":null,"name":null,"slug":null},"confidence":0.7,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-02-18T19:16:17.504Z","updated_at":"2026-09-21T18:07:17.391Z","links":{"self":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","events":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/events","classes":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/classes","camps":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/camps"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/places/slug/{slug}":{"get":{"tags":["Places"],"operationId":"getPlaceBySlug","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve a place by slug","description":"Returns the same place as `/v1/places/{id}`, addressed by slug instead of id.\n\n`slug` is unique per (metro, type). If the key can see this slug in more\nthan one metro, returns `400` with `details.metros`; pass `metro=` to\ndisambiguate. `include_archived=true` returns an archived row.\n\nReturns 503 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/SlugPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/IncludeArchived"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"}],"responses":{"200":{"description":"The place","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Place"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","type":"place","slug":"philly-art-center-queen-village","name":"Philly Art Center - Queen Village","description":"Philly Art Center's Queen Village studio offers classes, camps, and after-school programs for kids from infancy through tweens, plus adult classes in drawing, painting, printmaking, fibers, and clay. Programs include Creative Playgroup + Story Time (drop-in for 0-30 months), adult+child music and art classes, drop-off kids art classes (ages 2+), tween classes, summer camps (ages 4-13), vacation camps (ages 5-12), and after-school art with free school pick-up. Process over product philosophy — all materials included.","type_hint":"other","type_hint_notes":"Art studio / creative learning center","location":{"address":"514 Bainbridge St, Philadelphia, PA 19147, USA","street_address":"514 Bainbridge St, Philadelphia, PA 19147, USA","city":"Philadelphia","state":"PA","zip":"19147","lat":39.9408481,"lng":-75.1516337,"neighborhood":"Queen Village","neighborhood_slug":"queen-village"},"hours":{"monday":"Closed","tuesday":"Class hours vary","wednesday":"Class hours vary","thursday":"Class hours vary","friday":"Class hours vary","saturday":"Class hours vary","sunday":"Closed","notes":"Hours vary by class schedule. Check phillyartcenter.captyn.com for current session times.","exceptions":null},"admission":{"type":"paid","child_price":null,"adult_price":null,"infant_age_cutoff":null,"notes":"Varies by program. Tuition assistance available. 10% household discount.","currency":"USD"},"membership":{"available":false,"price_monthly":null,"price_annual":null,"notes":null,"currency":"USD"},"birthday_parties":{"available":false,"min_guests":null,"max_guests":null,"age_range":null,"booking_url":null,"notes":null},"classes":{"available":true,"types":["art","music","playgroup","after school art"],"age_range":"0-12 years","schedule_notes":"Fall Registration is LIVE!","registration_url":"https://phillyartcenter.com/kids-classes/"},"amenities":{"has_outdoor_space":false,"has_parking":false,"parking_notes":"Street parking on Bainbridge St and surrounding blocks.","has_wifi":false,"socks_required":false,"outside_food_allowed":true,"stroller_policy":null},"ages":{"min":0,"max":17,"text":"Playgroup: 0-30 months. Adult+child classes: 3-36 months. Kids classes: ages 2+. Tween classes available. Summer camps: 4-13. Vacation camps: 5-12.","audience":null,"bands":["baby","toddler","young_kids","bigger_kids"]},"audience":"teens","categories":["arts_creative"],"image_url":"https://a.mpcdn.io/pac/2023/04/pac-social-share.jpg?auto=compress%2Cformat&ixlib=php-3.3.1","images":["https://mpcdn.imgix.net/pac/26/04/web-banner_fnl-copy-2.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://mpcdn.imgix.net/pac/26/07/fall-classes_final-1.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://a.mpcdn.io/pac/2023/03/testimonial-bg.jpg?auto=compress%2Cformat&ixlib=php-3.3.1"],"website_url":"https://phillyartcenter.com/","organization":{"id":null,"name":null,"slug":null},"confidence":0.7,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-02-18T19:16:17.504Z","updated_at":"2026-09-21T18:07:17.391Z","links":{"self":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","events":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/events","classes":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/classes","camps":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/camps"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/organizations":{"get":{"tags":["Directory"],"operationId":"listOrganizations","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List organizations","description":"Returns every organization with at least one published, active listing in\nthe metro, with live counts by type. Without `q`, ordered by `name` then\n`id`, keyset-paged like the collections; the cursor is bound to `q` and\n`type`.\n\n**Finding a business.** Send `q` to look one up by what a person would\ntype: its name, its website address (`designgym.com`), or a pasted URL\n(`https://www.designgym.com/classes`). Casing, punctuation and spacing\nare ignored, as are endings such as `LLC`, `Inc`, `The`, `& Co` and\n`.com`/`.co`/`.org`/`.net`/`.io`/`.us`, and `design gym` finds\n`designgym`. A small typo (`desing gym`) still finds it. Both the\norganization's name and its website addresses are searched, whether or\nnot `website_url` is filled in.\n\nWith `q`, every result carries `score` and `match`, and results are\nordered by `score` (highest first), then `name`, then `id`. `score` is\n0 to 1, higher is closer, and is the same for one organization\nwhatever else is returned, so it can be shown as a confidence.\n`match` says how it was found: `exact_name` or `exact_domain` (the\nwhole name or address was typed), `name` or `domain` (the same words\nonce spelling, spacing and endings are set aside, or the start or a\nword of the name), or `fuzzy` (a small typo away). A `domain` match on a\ndifferent ending (`acme.org` for `acme.com`) is a suggestion to\nconfirm. Pages on shared platforms (social pages, booking widgets,\nwebsite builders) are never `exact_domain`. A `q` made only of words\nlike `the` or `and`, or of endings like `llc` or `.com`, returns an\nempty list with `meta.hint`. `page`, `limit` and `cursor` work as usual;\na cursor follows the same ranked order.\n\n`website_url` is the organization's own website. When none is recorded\nit is the address of the site the organization itself runs, if we\nhave one, and stays `null` when there is nothing trustworthy to show.\n\nReturns 501 when this endpoint is unavailable. Organization detail with\nits metros list is at `/v1/organizations/{id}`; listings themselves are\nthe collections filtered with `organization_id=`.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/DirectoryQ"},{"$ref":"#/components/parameters/DirectoryType"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts","organization_type":"recreation","website_url":"https://phillycircus.com","city":"Philadelphia","state":"PA","is_verified":false,"links":{"self":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","events":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/events","classes":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/classes","camps":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/camps","places":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/places"},"metro":"philadelphia","live":{"listings":19,"events":4,"classes":11,"camps":4,"places":0},"updated_at":"2026-09-26T13:45:37.633Z"}],"meta":{"metro":"example","limit":1,"count":1,"has_more":false}}},"find_a_business":{"summary":"Find a business by its website address (q=designgym.com)","value":{"data":[{"id":"a158148a-52d4-4ea3-a6b9-0c830ddc6768","name":"designgym.co","slug":"designgym-co","organization_type":"other","website_url":"https://www.designgym.co","city":"Philadelphia","state":"PA","is_verified":false,"links":{"self":"/v1/organizations/a158148a-52d4-4ea3-a6b9-0c830ddc6768","events":"/v1/organizations/a158148a-52d4-4ea3-a6b9-0c830ddc6768/events","classes":"/v1/organizations/a158148a-52d4-4ea3-a6b9-0c830ddc6768/classes","camps":"/v1/organizations/a158148a-52d4-4ea3-a6b9-0c830ddc6768/camps","places":"/v1/organizations/a158148a-52d4-4ea3-a6b9-0c830ddc6768/places"},"metro":"philadelphia","live":{"listings":6,"events":0,"classes":6,"camps":0,"places":0},"updated_at":"2026-09-26T13:45:37.633Z","score":0.94,"match":"domain"}],"meta":{"metro":"philadelphia","page":1,"limit":50,"count":1,"has_more":false,"next_cursor":null,"generated_at":"2026-09-30T12:00:00Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/neighborhoods":{"get":{"tags":["Directory"],"operationId":"listNeighborhoods","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List neighborhoods","description":"Returns the metro's neighborhoods with live listing counts by type,\nincluding zero-count rows. `slug` is the value `neighborhood=` takes\non the collection endpoints. Ordered by `name` then `id`; the default\npage size is `limit=200`.\n\nReturns 501 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/DirectoryQ"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NeighborhoodList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"9a9a9a9a-0000-4000-8000-000000000001","name":"University City","slug":"university-city","aliases":["UCity"],"lat":39.95,"lng":-75.2,"metro":"philadelphia","live":{"listings":40,"events":30,"classes":5,"camps":2,"places":3}}],"meta":{"metro":"example","limit":1,"count":1,"has_more":false}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/coverage":{"get":{"tags":["Coverage"],"operationId":"getMetroCoverage","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve metro coverage","description":"Returns coverage as a buyer would judge it for a metro: live counts by\ntype, how far ahead events run, how much of what is currently served\nis confirmed current, and how many rows carry an organization,\nneighborhood, place or coordinates.\n\nNumbers are computed from the same rows the collection endpoints\nserve. Responses may be cached according to `Cache-Control`;\nevery key entitled to the metro sees the same report. Returns 501\nwhen this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"}],"responses":{"200":{"description":"The report","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Coverage"}}},"examples":{"default":{"summary":"Example response","value":{"data":{"metro":"philadelphia","timezone":"America/New_York","counts":{"event":1583,"class":648,"camp":88,"place":983,"ongoing":16},"events":{"future":950,"next_7_days":165,"next_30_days":500,"future_recurring":460,"horizon":"2027-06-01T00:00:00Z"},"freshness":{"confirmed_last_7d_pct":62.3,"confirmed_last_30d_pct":84.1,"upcoming_48h_confirmed_12h_pct":58,"median_source_age_days":8.8},"fields":{"total":2335,"with_organization":2167,"with_neighborhood":1380,"with_place":1823,"with_coordinates":1340},"organizations":357,"sources":{"total":357},"generated_at":"2026-09-13T12:00:00Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/organizations/{id}":{"get":{"tags":["Organizations"],"operationId":"getOrganization","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve an organization","description":"The organization behind a listing's `organization` reference. Scope is checked against the metros the organization has live listings in.","parameters":[{"$ref":"#/components/parameters/IdPath"}],"responses":{"200":{"description":"The organization","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Organization"}}},"examples":{"default":{"summary":"Example response","value":{"data":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts","organization_type":"recreation","website_url":"https://phillycircus.com","city":"Philadelphia","state":"PA","is_verified":false,"links":{"self":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","events":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/events","classes":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/classes","camps":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/camps","places":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad/places"},"metro":"philadelphia","live":{"listings":19,"events":4,"classes":11,"camps":4,"places":0},"updated_at":"2026-09-26T13:45:37.633Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/listings/{id}/versions":{"get":{"tags":["Changes"],"operationId":"listListingVersions","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List listing versions","description":"Returns a privacy-safe summary of every change one listing has had,\nnewest first. Each item contains only its UTC time, a closed change\nkind, and the names of changed public fields. Values, internal actor\nnames, notes, and pipeline attributes are never returned. History is\nstill available after a listing is hard-deleted.\n\nPages with `cursor` set to the last `version_id` seen (`id < cursor`).\nA key not scoped to the listing's metro or type returns `404`, never\n`403`.\n","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/VersionsCursor"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"A page of versions","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"changed_at":"2026-09-10T06:12:05Z","kind":"date_changed","fields":["starts_at"]}],"meta":{"listing_id":"00000000-0000-4000-8000-000000000001","limit":1,"count":1,"has_more":false}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/changes":{"get":{"tags":["Changes"],"operationId":"listChanges","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List changes","description":"Returns every public-field change to a listing since `since`,\noldest first. To sync incrementally, keep the last `version_id` you\nsaw and pass it as `cursor`. Removals (`status` leaving `published`,\n`is_active` becoming `false`, or a hard delete) appear here even\nthough the resource itself returns `404`.\n\nEach item exposes only the change time, a closed change kind, and\nallowlisted public field names. Values, actors, pipeline attributes,\nand rows that touch only internal fields are never returned. Read\nfreshness from `source.crawled_at` (`include=source`) on the resource.\n","parameters":[{"name":"since","in":"query","required":true,"description":"Return changes with `changed_at` strictly after this instant.","schema":{"type":"string","format":"date-time"}},{"name":"metro","in":"query","description":"Restrict to one metro slug (must be in the key's scope).","schema":{"type":"string","pattern":"^[a-z0-9-]+$"}},{"name":"type","in":"query","description":"Restrict to one listing type.","schema":{"$ref":"#/components/schemas/ListingType"}},{"$ref":"#/components/parameters/ChangesCursor"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}}],"responses":{"200":{"description":"A page of changes","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"version_id":18231,"listing_id":"2f3c9d4e-3d2b-4b7d-9a3e-1b2c3d4e5f60","slug":"storytime-in-the-park-2026-09-12","type":"event","metro":"philadelphia","changed_at":"2026-09-10T06:12:05Z","kind":"date_changed","fields":["starts_at"]}],"meta":{"limit":1,"count":1,"has_more":false}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/activity":{"get":{"tags":["Activity"],"operationId":"getActivity","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Retrieve area activity","description":"Returns a single comparable activity score for a **point** (unlike\n`/around`, which resolves an **address** and returns grouped,\nranked results — this endpoint's job is the one number, not a\nresult set), the components behind it, and the specific listings\nnearby.\n\nGive **either** `lat` + `lng` **or** `address`. An `address` is\nresolved to a point server-side and biased to the metro. A request\nthat exceeds the key's geocoding allowance returns `429` naming the\nreset. `data.resolved_address` reports the address that was used and\nhow it was resolved (see `ResolvedLocation`); it is `null` for the\n`lat`/`lng` form.\n\nCounted rows are published, active, and coordinate-bearing, excluding\na source marked `gone`, anything quarantined, and coordinates that\nare an approximate resolution rather than a known place. Classes and\ncamps whose term has already ended are not counted: `activity_score`\nreflects what is ahead, not what has happened.\n\n`activity_score` is 0-100 and absolute, so it is comparable between\nmetros and over time. `percentile` ranks the same point against the\nmetro's reference distribution; it is `null` until comparison data\nis available. Diagnostic details are available only to internal keys.\n\nReturns 503 when this endpoint, or address resolution for the\n`address` form, is unavailable.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/PointLat"},{"$ref":"#/components/parameters/PointLng"},{"$ref":"#/components/parameters/Address"},{"$ref":"#/components/parameters/RadiusM"},{"$ref":"#/components/parameters/Days"},{"$ref":"#/components/parameters/Include"}],"responses":{"200":{"description":"The activity of the point.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivityResponse"},"examples":{"default":{"summary":"Example response","value":{"data":{"point":{"lat":1,"lng":1},"radius_m":1,"days":1,"components":{"events_30d":1,"events_per_week":1,"recurring_programs":1,"classes":1,"camps":1,"places_total":1,"places_by_type":{}},"activity_score":1,"summary":"example","evidence":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1}]},"meta":{"metro":"example","radius_m":1,"days":1,"generated_at":"2026-09-24T12:00:00.000Z"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/nearby":{"get":{"tags":["Activity"],"operationId":"listNearby","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List nearby listings","description":"Takes a **point** (`lat`/`lng`) and returns a flat, distance-ordered\nlist — no address resolution and no grouping, unlike `/around`, which\ntakes an **address** and returns grouped, ranked results. Use this\nwhen the caller already has coordinates; use `/around` when the\ncaller has an address.\n\nReturns published, active rows with coordinates within `radius_m` of\n`lat`/`lng`, nearest first, with the distance in metres on every row.\nOnly rows with something still ahead of them: places always, events\nthat have not started, and classes and camps whose term has not\nended.\n\nPaged by `cursor` only (there is no `page`); `meta.next_cursor` is\n`\"<distance_m>:<listing_id>\"`, the key of the last row returned, so\nthe page cannot drift as rows are written.\n\nResults are confined to `{metro}`; a point outside it returns an\nempty page rather than the neighboring metro's rows. `lat`/`lng`\nchoose where in the metro to look, never which metro to look in.\n\nUse `types` to narrow; each type requested must be in the key's\n`scopes.types`. Returns 503 when this endpoint is unavailable.\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/NearbyLat"},{"$ref":"#/components/parameters/NearbyLng"},{"$ref":"#/components/parameters/RadiusM"},{"$ref":"#/components/parameters/NearbyTypes"},{"$ref":"#/components/parameters/NearbyCursor"},{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"A page of nearby items, nearest first.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NearbyList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1}],"meta":{"limit":1,"count":1,"has_more":false}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/{metro}/around":{"get":{"tags":["Address search"],"operationId":"searchAroundAddress","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"Search around an address","x-stability":"beta","description":"Takes an **address** (or `lat`/`lng`, resolved the same way) and\nreturns everything nearby, grouped the way a person reads a\nneighborhood rather than as one flat relevance list. `/nearby` is the\npoint-only sibling: a plain distance-ordered list, no address\nresolution, no grouping — use it when the caller already has\ncoordinates.\n\nOne request returns:\n\n* `location` — the resolved address, so you can see which reading of\n  an ambiguous address was used;\n* `activity` — a header: score, percentile, one sentence, components;\n* `results` — five ranked groups, each item carrying `distance_m` and\n  `walk_minutes`;\n* `facets` — counts by type, age band, free/paid and distance ring\n  over the whole circle;\n* `coverage` — how many nearby rows are excluded for lacking\n  coordinates.\n\nCheck `coverage` before treating an empty group as a signal: an empty\ngroup with `coverage.hidden_nearby > 0` means those rows are not\nvisible to this endpoint, not that the area has nothing happening.\n\nThe groups: `happening_soon` (dated events in the window),\n`recurring_programs` (weekly/monthly series and drop-in classes),\n`classes_enrolling` (term classes), `camps`, and `places` (places with\nno date of their own). `happening_soon` and `recurring_programs`\noverlap by design; each item's `also_in` names the other groups it\nappears in.\n\nResults are ordered for relevance to the requested point, window and\nfilters. Diagnostic ranking details are available only to internal keys.\n\n`limit` is **per group**. Each group returns its own `next_cursor`\n(`\"<group>:<offset>\"`); pass it as `cursor` to continue that one\ngroup.\n\nThe window is `from`/`to`, local calendar dates in the metro's\ntimezone: `from` defaults to today, `to` to `from` + 30 days, `to` is\ninclusive of that whole local day, and the span is at most 366 days.\nUnlike the collection endpoints, this route never returns an instant\nbefore now — a `from` of today (or earlier) starts at the present,\nnot local midnight.\n`meta.window` echoes the resolved dates.\n\n`min_confidence` uses the default shown in this operation. Collection\nendpoints may use different documented defaults.\n\nReturns 503 when this endpoint is unavailable.\n\n**Beta — may not be enabled for all keys yet.** If location resolution\nis unavailable, returns `503` (`\"geocoding unavailable\"`) rather than\nguessing. `data.location.source` says how the location was resolved\n(see `ResolvedLocation`).\n","parameters":[{"$ref":"#/components/parameters/MetroPath"},{"$ref":"#/components/parameters/PointLat"},{"$ref":"#/components/parameters/PointLng"},{"$ref":"#/components/parameters/Address"},{"$ref":"#/components/parameters/AroundRadiusM"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/AroundAges"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/AroundTypes"},{"$ref":"#/components/parameters/AroundMinConfidence"},{"$ref":"#/components/parameters/AroundLimit"},{"$ref":"#/components/parameters/AroundCursor"},{"$ref":"#/components/parameters/Include"}],"responses":{"200":{"description":"The resolved location, the activity header, grouped results, facets and coverage.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AroundResponse"},"examples":{"default":{"summary":"Example response","value":{"data":{"location":{"lat":1,"lng":1,"source":"cache"},"results":{"happening_soon":{"total":1,"returned":1,"items":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1,"walk_minutes":1,"score":1}]},"recurring_programs":{"total":1,"returned":1,"items":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1,"walk_minutes":1,"score":1}]},"classes_enrolling":{"total":1,"returned":1,"items":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1,"walk_minutes":1,"score":1}]},"camps":{"total":1,"returned":1,"items":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1,"walk_minutes":1,"score":1}]},"places":{"total":1,"returned":1,"items":[{"listing_id":"00000000-0000-4000-8000-000000000001","type":"event","name":"example","distance_m":1,"walk_minutes":1,"score":1}]}},"facets":{"by_type":{},"by_age_band":{},"by_price":{"free":1,"paid":1},"free_share":1,"by_distance_ring":[{"label":"within_400m","max_m":1,"count":1}]},"coverage":{"hidden_nearby":1,"unplaceable_in_metro":1,"reason":"example"}},"meta":{"metro":"example","radius_m":1,"window":{"from":"2026-09-24","to":"2026-09-24","timezone":"example"},"limit":1}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/places/{id}/events":{"get":{"tags":["Events"],"operationId":"listPlaceEvents","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List place events","description":"Same as `GET /v1/{metro}/events?place_id={id}`, addressed by the place instead of the metro.\n\nResolves the place by id, `404`s if it does not exist, takes the metro from the place's own row, and delegates to the ordinary events list — every other list parameter (paging, `fields=`, `include=`, date windows, `min_confidence`, ...) keeps working exactly as it does there. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the place's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Team"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/HasTime"},{"$ref":"#/components/parameters/Recurring"},{"$ref":"#/components/parameters/Indoor"},{"$ref":"#/components/parameters/Outdoor"},{"$ref":"#/components/parameters/Sensory"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of events. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":"2026-10-14","min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","to","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/places/{id}/classes":{"get":{"tags":["Classes"],"operationId":"listPlaceClasses","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List place classes","description":"Same as `GET /v1/{metro}/classes?place_id={id}`, addressed by the place instead of the metro.\n\nResolves the place by id, `404`s if it does not exist, takes the metro from the place's own row, and delegates to the ordinary classes list — every other list parameter (paging, `fields=`, `include=`, date windows, `min_confidence`, ...) keeps working exactly as it does there. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the place's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/Openings"},{"name":"schedule_day","in":"query","description":"Keep classes that meet on this weekday.","schema":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}},{"name":"enrollment_type","in":"query","description":"Keep rows matching this enrollment type.","schema":{"type":"string","enum":["enrollment","unknown"]}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of classes. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"c57d9bae-6479-41c5-9176-f314fa4d31f4","type":"class","slug":"kids-pottery-classes-b3d835f7","name":"Kids Pottery Classes","description":"6-week pottery classes for kids ages 8-16, focusing on wheel-throwing and hand-building techniques.","program":{"enrollment_type":"enrollment","skill_level_notes":"all levels","adult_participation":null,"what_youll_learn":null,"prerequisites":null},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"schedule":{"type":"session","days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"tuition":{"amount":185,"from":185,"text":"$185 for 6-week session","drop_in_price":null,"trial_price":null,"trial_notes":null,"currency":"USD"},"price":{"type":"fixed","min":185,"max":185,"scope":"admission","note":"$185 for 6-week session","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":8,"max":16,"text":"Early Elementary, Tweens, Teens","audience":"kids","bands":["bigger_kids"]},"audience":"teens","traits":{"seasons":["fall","winter"]},"place":{"id":"1af0824d-36cf-482d-a6d7-073343ae52ed","slug":"earth-center-pottery-ebc6fdd7","name":"Earth Center Pottery"},"location":{"address":"10 Stable Mill Trl, Richboro, PA 18954, USA","street_address":"10 Stable Mill Trl, Richboro, PA 18954, USA","city":"Richboro","state":"PA","zip":"18954","lat":40.2226282,"lng":-74.9866812,"neighborhood":"Somerton","neighborhood_slug":"somerton"},"categories":["arts_creative"],"occasions":[],"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","opens_at":null,"spots_remaining":null,"has_spots_available":true,"waitlist_available":false,"sections_with_spots":1},"sections_total":1,"sections":[{"id":"0b8a3f5e-52c4-4d64-9a0e-2f6d7c1e9a11","name":"Tuesday afternoon","schedule":{"days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"ages":{"min":8,"max":16,"text":null},"tuition":{"amount":185,"text":"$185 for 6-week session","drop_in_price":null,"currency":"USD"},"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","spots_remaining":null,"has_spots_available":true,"waitlist_available":false},"updated_at":"2026-09-26T12:01:08.782Z"}],"sessions":[],"image_url":"https://earthcenterpottery.com/wp-content/uploads/2024/02/IMG_0318-scaled-e1707359564209-1024x566.jpg","organization":{"id":"37bae48b-e86c-44a4-80d7-29fd9c34443c","name":"Earth Center Pottery","slug":"earthcenterpotterycom-f09a2fcc"},"confidence":0.45,"verified_at":"2026-09-26T12:00:21.748Z","metro":"philadelphia","status":"published","created_at":"2026-07-17T16:01:41.805Z","updated_at":"2026-09-26T12:01:08.782Z","links":{"self":"/v1/classes/c57d9bae-6479-41c5-9176-f314fa4d31f4","place":"/v1/places/1af0824d-36cf-482d-a6d7-073343ae52ed","organization":"/v1/organizations/37bae48b-e86c-44a4-80d7-29fd9c34443c"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/places/{id}/camps":{"get":{"tags":["Camps"],"operationId":"listPlaceCamps","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List place camps","description":"Same as `GET /v1/{metro}/camps?place_id={id}`, addressed by the place instead of the metro.\n\nResolves the place by id, `404`s if it does not exist, takes the metro from the place's own row, and delegates to the ordinary camps list — every other list parameter (paging, `fields=`, `include=`, date windows, `min_confidence`, ...) keeps working exactly as it does there. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the place's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/Free"},{"name":"year","in":"query","description":"The camp's year.","schema":{"type":"integer","minimum":2020,"maximum":2100}},{"name":"overnight","in":"query","description":"Keep only overnight camps.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/OrganizationId"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of camps. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","type":"camp","slug":"2026-summer-circus-camp-e49f4a3a","name":"2026 Summer Circus Camp","description":"The Philadelphia School of Circus Arts – Best of Philly Winner for “Kids Classes” – announces Summer Circus Camp 2026 for youth ages 4 – 15. Circus Camp returns with our 1-week camp program designed for campers with an emphasis on play and exploration in the exciting world of circus. Campers will learn static trapeze, aerial sling, aerial fabric, wire walking, juggling, plate-spinning, rolling globe, tumbling, unicycling, clowning and more. We can’t wait to share the excitement and challenge of the circus with kids in our full-day program!","season":"summer","year":2026,"starts_on":"2026-06-01","ends_on":"2026-06-05","schedule":{"type":null,"is_full_day":true,"is_half_day_am":false,"is_half_day_pm":false,"day_start_time":"09:00:00","day_end_time":"15:00:00","extended_care":{"morning_start":null,"morning_price":null,"afternoon_end":null,"afternoon_price":null,"notes":"Before Care: $20/day; After Care: $35/day","currency":"USD"},"timezone":"America/New_York"},"is_overnight":false,"is_travel":false,"is_specialty":false,"pricing_unit":"per_week","price":{"type":"fixed","min":495,"max":495,"scope":"admission","note":"$495/week","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":4,"max":15,"text":null,"audience":null,"bands":["young_kids","bigger_kids"]},"audience":"teens","traits":{"seasons":["summer"]},"place":{"id":"1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","slug":"philadelphia-school-of-circus-arts-62377244","name":"Philadelphia School of Circus Arts"},"location":{"address":"6452 Greene Street","street_address":"6452 Greene Street","city":"Philadelphia","state":"PA","zip":"19119","lat":40.0419162,"lng":-75.1896032,"neighborhood":"Northwest Philadelphia","neighborhood_slug":null},"categories":["sports_active_play"],"registration":{"url":"https://portal.iclasspro.com/phillycircus/booking","opens_on":null,"deadline_on":null,"early_bird_deadline_on":null,"has_spots_available":true,"sessions_with_spots":1},"sessions":[{"id":"4fbe88ce-c939-450e-92a0-e92c3f04ed6c","name":"Summer Circus Camp 2026","starts_on":"2026-06-01","ends_on":"2026-06-05","price":495,"early_bird_price":null,"full_day_price":null,"half_day_price":null,"currency":"USD","capacity":null,"spots_remaining":null,"status":"open","theme":null,"notes":null}],"image_url":"https://phillycircus.com/wp-content/uploads/PSCA-web-promo-01.jpg","organization":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts"},"confidence":0.55,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-09-22T06:11:27.636Z","updated_at":"2026-09-26T08:19:23.038Z","links":{"self":"/v1/camps/7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","place":"/v1/places/1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","organization":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/organizations/{id}/events":{"get":{"tags":["Events"],"operationId":"listOrganizationEvents","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List organization events","description":"Same as `GET /v1/{metro}/events?organization_id={id}`, addressed by the organization instead of the metro.\n\nResolves the organization by id, `404`s if it does not exist, and takes the metro from that row. An organization with live listings in more than one metro is a `400` asking for `metro=` to disambiguate, exactly like a slug that is not unique across the key's metros; give it and the ambiguity is resolved the same way. Every other list parameter keeps working. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the organization's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Team"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/HasTime"},{"$ref":"#/components/parameters/Recurring"},{"$ref":"#/components/parameters/Indoor"},{"$ref":"#/components/parameters/Outdoor"},{"$ref":"#/components/parameters/Sensory"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of events. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"b81a95d2-1d4e-46fd-9cff-322a41e429ad","type":"event","slug":"toddler-time-ages-5-and-under-toddler-time-observer-e50d61ea","name":"Toddler Time (Ages 5 and Under) / Toddler Time Observer","description":"Includes Treehouses and Free Play Areas for toddlers ages 5 and under.","starts_local":"2026-09-14T09:30:00","ends_local":null,"start_time":"09:30:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-14T13:30:00.000Z","ends_at":null,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR","recurrence_description":null,"place":{"id":"9cde4494-6c2a-4bfc-b15a-22edce13f3f7","slug":"treehouse-world-d34361f7","name":"Treehouse World"},"location":{"address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","street_address":"1442 Phoenixville Pike, West Chester, PA 19380, USA","city":"West Chester","state":"PA","zip":"19380","lat":40.0240296,"lng":-75.5858949,"neighborhood":"Newtown Square","neighborhood_slug":"newtown-square"},"price":{"type":"fixed","min":12,"max":12,"scope":"admission","note":"$12.00","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":1,"max":5,"text":null,"audience":"kids","bands":["baby","toddler","young_kids"]},"audience":"kids","traits":{"seasons":["fall"]},"categories":["social_play_spaces"],"occasions":[],"teams":[],"registration_url":"https://treehouseworld.com/pages/admission-prices","ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"c45b9b3a-45ab-4f9c-b2e2-986dcb921f25","name":"Treehouse World","slug":"treehouseworldcom-a86bfd79"},"confidence":1,"verified_at":"2026-09-26T14:06:38.332Z","metro":"philadelphia","status":"published","created_at":"2026-09-14T08:04:04.969Z","updated_at":"2026-09-26T14:06:38.788Z","links":{"self":"/v1/events/b81a95d2-1d4e-46fd-9cff-322a41e429ad","place":"/v1/places/9cde4494-6c2a-4bfc-b15a-22edce13f3f7","organization":"/v1/organizations/c45b9b3a-45ab-4f9c-b2e2-986dcb921f25"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":"2026-10-14","min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","to","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/organizations/{id}/classes":{"get":{"tags":["Classes"],"operationId":"listOrganizationClasses","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List organization classes","description":"Same as `GET /v1/{metro}/classes?organization_id={id}`, addressed by the organization instead of the metro.\n\nResolves the organization by id, `404`s if it does not exist, and takes the metro from that row. An organization with live listings in more than one metro is a `400` asking for `metro=` to disambiguate, exactly like a slug that is not unique across the key's metros; give it and the ambiguity is resolved the same way. Every other list parameter keeps working. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the organization's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Occasion"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"$ref":"#/components/parameters/Openings"},{"$ref":"#/components/parameters/Indoor"},{"$ref":"#/components/parameters/Outdoor"},{"$ref":"#/components/parameters/Sensory"},{"name":"schedule_day","in":"query","description":"Keep classes that meet on this weekday.","schema":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}},{"name":"enrollment_type","in":"query","description":"Keep rows matching this enrollment type.","schema":{"type":"string","enum":["enrollment","unknown"]}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Weekday"},{"$ref":"#/components/parameters/StartAfter"},{"$ref":"#/components/parameters/StartBefore"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of classes. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClassList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"c57d9bae-6479-41c5-9176-f314fa4d31f4","type":"class","slug":"kids-pottery-classes-b3d835f7","name":"Kids Pottery Classes","description":"6-week pottery classes for kids ages 8-16, focusing on wheel-throwing and hand-building techniques.","program":{"enrollment_type":"enrollment","skill_level_notes":"all levels","adult_participation":null,"what_youll_learn":null,"prerequisites":null},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"schedule":{"type":"session","days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"tuition":{"amount":185,"from":185,"text":"$185 for 6-week session","drop_in_price":null,"trial_price":null,"trial_notes":null,"currency":"USD"},"price":{"type":"fixed","min":185,"max":185,"scope":"admission","note":"$185 for 6-week session","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":8,"max":16,"text":"Early Elementary, Tweens, Teens","audience":"kids","bands":["bigger_kids"]},"audience":"teens","traits":{"seasons":["fall","winter"]},"place":{"id":"1af0824d-36cf-482d-a6d7-073343ae52ed","slug":"earth-center-pottery-ebc6fdd7","name":"Earth Center Pottery"},"location":{"address":"10 Stable Mill Trl, Richboro, PA 18954, USA","street_address":"10 Stable Mill Trl, Richboro, PA 18954, USA","city":"Richboro","state":"PA","zip":"18954","lat":40.2226282,"lng":-74.9866812,"neighborhood":"Somerton","neighborhood_slug":"somerton"},"categories":["arts_creative"],"occasions":[],"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","opens_at":null,"spots_remaining":null,"has_spots_available":true,"waitlist_available":false,"sections_with_spots":1},"sections_total":1,"sections":[{"id":"0b8a3f5e-52c4-4d64-9a0e-2f6d7c1e9a11","name":"Tuesday afternoon","schedule":{"days":["tuesday"],"start_time":"16:00:00","end_time":"18:00:00","duration_minutes":120,"rrule":"FREQ=WEEKLY;BYDAY=TU","notes":"Tuesdays (4:00 pm – 6:00 pm)","timezone":"America/New_York"},"term":{"name":null,"starts_on":"2026-09-29","ends_on":"2026-12-15","total_classes":null},"ages":{"min":8,"max":16,"text":null},"tuition":{"amount":185,"text":"$185 for 6-week session","drop_in_price":null,"currency":"USD"},"registration":{"url":"https://www.cognitoforms.com/TylerParkCenterForTheArts/KidsPotteryClasses","status":"open","spots_remaining":null,"has_spots_available":true,"waitlist_available":false},"updated_at":"2026-09-26T12:01:08.782Z"}],"sessions":[],"image_url":"https://earthcenterpottery.com/wp-content/uploads/2024/02/IMG_0318-scaled-e1707359564209-1024x566.jpg","organization":{"id":"37bae48b-e86c-44a4-80d7-29fd9c34443c","name":"Earth Center Pottery","slug":"earthcenterpotterycom-f09a2fcc"},"confidence":0.45,"verified_at":"2026-09-26T12:00:21.748Z","metro":"philadelphia","status":"published","created_at":"2026-07-17T16:01:41.805Z","updated_at":"2026-09-26T12:01:08.782Z","links":{"self":"/v1/classes/c57d9bae-6479-41c5-9176-f314fa4d31f4","place":"/v1/places/1af0824d-36cf-482d-a6d7-073343ae52ed","organization":"/v1/organizations/37bae48b-e86c-44a4-80d7-29fd9c34443c"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/organizations/{id}/camps":{"get":{"tags":["Camps"],"operationId":"listOrganizationCamps","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List organization camps","description":"Same as `GET /v1/{metro}/camps?organization_id={id}`, addressed by the organization instead of the metro.\n\nResolves the organization by id, `404`s if it does not exist, and takes the metro from that row. An organization with live listings in more than one metro is a `400` asking for `metro=` to disambiguate, exactly like a slug that is not unique across the key's metros; give it and the ambiguity is resolved the same way. Every other list parameter keeps working. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the organization's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/MinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Season"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"$ref":"#/components/parameters/PlaceId"},{"$ref":"#/components/parameters/Free"},{"name":"year","in":"query","description":"The camp's year.","schema":{"type":"integer","minimum":2020,"maximum":2100}},{"name":"overnight","in":"query","description":"Keep only overnight camps.","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/MaxPrice"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of camps. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","type":"camp","slug":"2026-summer-circus-camp-e49f4a3a","name":"2026 Summer Circus Camp","description":"The Philadelphia School of Circus Arts – Best of Philly Winner for “Kids Classes” – announces Summer Circus Camp 2026 for youth ages 4 – 15. Circus Camp returns with our 1-week camp program designed for campers with an emphasis on play and exploration in the exciting world of circus. Campers will learn static trapeze, aerial sling, aerial fabric, wire walking, juggling, plate-spinning, rolling globe, tumbling, unicycling, clowning and more. We can’t wait to share the excitement and challenge of the circus with kids in our full-day program!","season":"summer","year":2026,"starts_on":"2026-06-01","ends_on":"2026-06-05","schedule":{"type":null,"is_full_day":true,"is_half_day_am":false,"is_half_day_pm":false,"day_start_time":"09:00:00","day_end_time":"15:00:00","extended_care":{"morning_start":null,"morning_price":null,"afternoon_end":null,"afternoon_price":null,"notes":"Before Care: $20/day; After Care: $35/day","currency":"USD"},"timezone":"America/New_York"},"is_overnight":false,"is_travel":false,"is_specialty":false,"pricing_unit":"per_week","price":{"type":"fixed","min":495,"max":495,"scope":"admission","note":"$495/week","unit":"per_session","is_free":false,"currency":"USD"},"ages":{"min":4,"max":15,"text":null,"audience":null,"bands":["young_kids","bigger_kids"]},"audience":"teens","traits":{"seasons":["summer"]},"place":{"id":"1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","slug":"philadelphia-school-of-circus-arts-62377244","name":"Philadelphia School of Circus Arts"},"location":{"address":"6452 Greene Street","street_address":"6452 Greene Street","city":"Philadelphia","state":"PA","zip":"19119","lat":40.0419162,"lng":-75.1896032,"neighborhood":"Northwest Philadelphia","neighborhood_slug":null},"categories":["sports_active_play"],"registration":{"url":"https://portal.iclasspro.com/phillycircus/booking","opens_on":null,"deadline_on":null,"early_bird_deadline_on":null,"has_spots_available":true,"sessions_with_spots":1},"sessions":[{"id":"4fbe88ce-c939-450e-92a0-e92c3f04ed6c","name":"Summer Circus Camp 2026","starts_on":"2026-06-01","ends_on":"2026-06-05","price":495,"early_bird_price":null,"full_day_price":null,"half_day_price":null,"currency":"USD","capacity":null,"spots_remaining":null,"status":"open","theme":null,"notes":null}],"image_url":"https://phillycircus.com/wp-content/uploads/PSCA-web-promo-01.jpg","organization":{"id":"c6e39d31-abce-43f8-bccd-2cf5ce73a0ad","name":"Philadelphia School of Circus Arts","slug":"philadelphia-school-of-circus-arts"},"confidence":0.55,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-09-22T06:11:27.636Z","updated_at":"2026-09-26T08:19:23.038Z","links":{"self":"/v1/camps/7fb56a77-8603-4c31-a07f-ef9d9e7f53e3","place":"/v1/places/1730e947-3dd8-45ad-88f5-2fe7cdeec9e8","organization":"/v1/organizations/c6e39d31-abce-43f8-bccd-2cf5ce73a0ad"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"from":"2026-09-14","to":null,"min_confidence":0.7,"audience":["not_adults"]},"defaults_applied":["from","min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/organizations/{id}/places":{"get":{"tags":["Places"],"operationId":"listOrganizationPlaces","x-access":{"plan":"all","credits":"1 per record (planned)"},"summary":"List organization places","description":"Same as `GET /v1/{metro}/places?organization_id={id}`, addressed by the organization instead of the metro.\n\nResolves the organization by id, `404`s if it does not exist, and takes the metro from that row. An organization with live listings in more than one metro is a `400` asking for `metro=` to disambiguate, exactly like a slug that is not unique across the key's metros; give it and the ambiguity is resolved the same way. Every other list parameter keeps working. Same auth, metro scope, rate limiting and metering as the list endpoint; a key without access to the organization's metro gets the same `403` the list endpoint gives.","parameters":[{"$ref":"#/components/parameters/IdPath"},{"$ref":"#/components/parameters/MetroQuery"},{"$ref":"#/components/parameters/PlaceMinConfidence"},{"$ref":"#/components/parameters/Category"},{"$ref":"#/components/parameters/Audience"},{"$ref":"#/components/parameters/Age"},{"$ref":"#/components/parameters/Neighborhood"},{"$ref":"#/components/parameters/Lat"},{"$ref":"#/components/parameters/Lng"},{"$ref":"#/components/parameters/ListRadiusM"},{"$ref":"#/components/parameters/Zip"},{"$ref":"#/components/parameters/NearZip"},{"$ref":"#/components/parameters/IncludeApproximate"},{"name":"type_hint","in":"query","description":"Filters on the place's type (see `Place.type_hint`).","schema":{"$ref":"#/components/schemas/PlaceTypeHint"}},{"name":"place_type","in":"query","deprecated":true,"description":"The deprecated spelling of `type_hint`. Still read; `type_hint` wins when both are given.","schema":{"$ref":"#/components/schemas/PlaceTypeHint"}},{"name":"has_birthday_parties","in":"query","schema":{"type":"boolean"}},{"name":"has_classes","in":"query","schema":{"type":"boolean"}},{"$ref":"#/components/parameters/Sensory"},{"$ref":"#/components/parameters/ChangedSince"},{"$ref":"#/components/parameters/Q"},{"$ref":"#/components/parameters/Fields"},{"$ref":"#/components/parameters/Expand"},{"$ref":"#/components/parameters/Include"},{"$ref":"#/components/parameters/IncludeMode"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/Facets"},{"$ref":"#/components/parameters/ListLimit"}],"responses":{"200":{"description":"A page of places. Each item carries `confidence`; `source` appears only when requested with `include=source` (a paid add-on).","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimit-Limit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimit-Remaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"ETag":{"$ref":"#/components/headers/ETag"},"Cache-Control":{"$ref":"#/components/headers/Cache-Control"},"Vary":{"$ref":"#/components/headers/Vary"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceList"},"examples":{"default":{"summary":"Example response","value":{"data":[{"id":"1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","type":"place","slug":"philly-art-center-queen-village","name":"Philly Art Center - Queen Village","description":"Philly Art Center's Queen Village studio offers classes, camps, and after-school programs for kids from infancy through tweens, plus adult classes in drawing, painting, printmaking, fibers, and clay. Programs include Creative Playgroup + Story Time (drop-in for 0-30 months), adult+child music and art classes, drop-off kids art classes (ages 2+), tween classes, summer camps (ages 4-13), vacation camps (ages 5-12), and after-school art with free school pick-up. Process over product philosophy — all materials included.","type_hint":"other","type_hint_notes":"Art studio / creative learning center","location":{"address":"514 Bainbridge St, Philadelphia, PA 19147, USA","street_address":"514 Bainbridge St, Philadelphia, PA 19147, USA","city":"Philadelphia","state":"PA","zip":"19147","lat":39.9408481,"lng":-75.1516337,"neighborhood":"Queen Village","neighborhood_slug":"queen-village"},"hours":{"monday":"Closed","tuesday":"Class hours vary","wednesday":"Class hours vary","thursday":"Class hours vary","friday":"Class hours vary","saturday":"Class hours vary","sunday":"Closed","notes":"Hours vary by class schedule. Check phillyartcenter.captyn.com for current session times.","exceptions":null},"admission":{"type":"paid","child_price":null,"adult_price":null,"infant_age_cutoff":null,"notes":"Varies by program. Tuition assistance available. 10% household discount.","currency":"USD"},"membership":{"available":false,"price_monthly":null,"price_annual":null,"notes":null,"currency":"USD"},"birthday_parties":{"available":false,"min_guests":null,"max_guests":null,"age_range":null,"booking_url":null,"notes":null},"classes":{"available":true,"types":["art","music","playgroup","after school art"],"age_range":"0-12 years","schedule_notes":"Fall Registration is LIVE!","registration_url":"https://phillyartcenter.com/kids-classes/"},"amenities":{"has_outdoor_space":false,"has_parking":false,"parking_notes":"Street parking on Bainbridge St and surrounding blocks.","has_wifi":false,"socks_required":false,"outside_food_allowed":true,"stroller_policy":null},"ages":{"min":0,"max":17,"text":"Playgroup: 0-30 months. Adult+child classes: 3-36 months. Kids classes: ages 2+. Tween classes available. Summer camps: 4-13. Vacation camps: 5-12.","audience":null,"bands":["baby","toddler","young_kids","bigger_kids"]},"audience":"teens","categories":["arts_creative"],"image_url":"https://a.mpcdn.io/pac/2023/04/pac-social-share.jpg?auto=compress%2Cformat&ixlib=php-3.3.1","images":["https://mpcdn.imgix.net/pac/26/04/web-banner_fnl-copy-2.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://mpcdn.imgix.net/pac/26/07/fall-classes_final-1.png?auto=compress%2Cformat&ixlib=php-3.3.1","https://a.mpcdn.io/pac/2023/03/testimonial-bg.jpg?auto=compress%2Cformat&ixlib=php-3.3.1"],"website_url":"https://phillyartcenter.com/","organization":{"id":null,"name":null,"slug":null},"confidence":0.7,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-02-18T19:16:17.504Z","updated_at":"2026-09-21T18:07:17.391Z","links":{"self":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e","events":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/events","classes":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/classes","camps":"/v1/places/1aed87ca-ab4f-4fc0-baaa-8c6ebeefa10e/camps"}}],"meta":{"limit":1,"count":1,"has_more":false,"applied_filters":{"min_confidence":0.5,"audience":["not_adults"]},"defaults_applied":["min_confidence","audience"]}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"501":{"$ref":"#/components/responses/NotImplemented"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"**Data plane only (`/v1`).** Issued per client.\nFormat `tl_<8 hex>_<48 hex>`; only a hash of the key is stored, and\nthe `tl_<8 hex>` prefix is kept for display. Validated server-side\non every request.\n\nThis credential is **rejected everywhere under `/platform`**. An API key\nmust not be able to mint API keys: a leaked read key would otherwise be\naccount takeover.\n"}},"headers":{"Allow":{"description":"The methods this path serves. Always `GET, HEAD, OPTIONS` — the API is read-only.","schema":{"type":"string"},"example":"GET, HEAD, OPTIONS"},"Cache-Control":{"description":"Always `private` on `/v1`: every response is shaped by the calling key's\nscope, so no shared cache may store one. `max-age=60` on collections and\n`/around`, `300` on details, `3600` on `/v1/metros`, `no-cache` on\n`/v1/changes` (store it, but revalidate every read — `is_live` reflects\nthe current row). Every error is `no-store`.\n","schema":{"type":"string"},"example":"private, max-age=60"},"ETag":{"description":"A **weak** validator (`W/\"…\"`) over the whole representation except\n`meta.generated_at`, which is a reading of the clock rather than a\nstatement about the data. Weak because two responses sharing one are\nequivalent but not octet-equal, which is exactly what RFC 9110 §8.8.1\nreserves a strong validator against claiming.\n\nSend it back as `If-None-Match` — on detail routes as much as on lists —\nand an unchanged answer costs a `304` with no body. The calling key's\nscope is folded into the digest, so two keys entitled to different\nmetros can never collide on one validator.\n","schema":{"type":"string"},"example":"W/\"TD64uXep9BDu_tA9n6OF_Zwl3IA\""},"Vary":{"description":"`Accept-Encoding, X-API-Key` on every `/v1` response. The key is in\nthere because every route on this surface answers `200` with a\ncredential and `401` without one, so the representation depends on the\nheader whether or not two *valid* keys would differ.\n","schema":{"type":"string"},"example":"Accept-Encoding, X-API-Key"},"RateLimit-Limit":{"description":"Requests allowed per minute for this key. Same value as\n`X-RateLimit-Limit`; this is the IETF `RateLimit-*` spelling and the\none to prefer in new clients. Both families are sent deliberately.\n","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current minute window. Same value as `X-RateLimit-Remaining`.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"**Seconds from now** until the window resets — a delta, per the IETF\ndraft. Note that `X-RateLimit-Reset` carries the same moment as a unix\n**timestamp**: the two families agree on the instant and disagree on\nhow to spell it. Do not read one as the other.\n","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Requests included in this UTC calendar month for the client the key\nbelongs to (the plan's included requests, or a per-client override).\nAbsent on an unlimited plan, and absent while the shared limiter is\ndegraded — a missing quota header means \"not known\", never \"no limit\".\n","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Requests left in the monthly allowance. `0` while serving overage.","schema":{"type":"integer"}},"X-Quota-Reset":{"description":"Unix time (seconds) at the start of the next UTC month, when the allowance resets.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key: the plan's ceiling (or the per-client override) plus `burst`. The key's own rate limit can only narrow that — it is clamped to the ceiling, never above it. A key with no override is enforced at the ceiling.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets.","schema":{"type":"integer"}},"X-Request-Id":{"description":"Correlation id; echoed in error bodies and recorded against the account's usage.","schema":{"type":"string"}},"Retry-After":{"description":"Seconds to wait before retrying. Sent with `429` (both codes) and with\n`503`. Deliberately **absent** on `501`, where waiting cannot help.\n","schema":{"type":"integer"}}},"parameters":{"MetroPath":{"name":"metro","in":"path","required":true,"description":"Metro slug from `/v1/metros` (e.g. `philadelphia`). Must be in the key's `scopes.metros`.","schema":{"type":"string","pattern":"^[a-z0-9-]+$"}},"IdPath":{"name":"id","in":"path","required":true,"description":"Listing id.","schema":{"type":"string","format":"uuid"}},"SlugPath":{"name":"slug","in":"path","required":true,"description":"Listing slug — the segment a consumer already has in\nits own URLs. Unique per (metro, type), **not** globally: when a key\ncan see the same slug in more than one metro the answer is a `400`\nlisting them in `details.metros`, and `metro` picks one.\n","schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,127}$"}},"MetroQuery":{"name":"metro","in":"query","description":"Which metro's row is meant, when a slug is not unique across the key's metros.","schema":{"type":"string","pattern":"^[a-z0-9-]+$"}},"IncludeArchived":{"name":"include_archived","in":"query","description":"Also serve a listing whose `status` is `archived` — a permalink that\nshould still render, with a \"this has passed\" banner, rather than\n404. Detail routes only; a list never returns archived rows. Drafts\nare never served. Returns 503 when archived-row support is\nunavailable.\n","schema":{"type":"boolean","default":false}},"PlaceId":{"name":"place_id","in":"query","description":"Keep rows held at this place (`place.id`).","schema":{"type":"string","format":"uuid"}},"From":{"name":"from","in":"query","description":"Local calendar date (metro timezone), inclusive. Defaults to today in the metro. The value used is echoed in `meta.applied_filters.from`.","schema":{"type":"string","format":"date"}},"To":{"name":"to","in":"query","description":"Local calendar date (metro timezone), inclusive; at most 366 days after `from`.\n**On events it defaults to `from` + 30 days**, so a list with no `to` covers one\nmonth; pass a later `to` for a longer view. Classes and camps have no default:\nwith `from` alone the window is open-ended. The value used is echoed in\n`meta.applied_filters.to`.\n","schema":{"type":"string","format":"date"}},"MinConfidence":{"name":"min_confidence","in":"query","description":"Drop rows whose `confidence` is below this. **Defaults to `0.7`** on events, classes\nand camps, so rows below that are not returned unless you lower it; `0` disables the\nfilter. The value used is echoed in `meta.applied_filters.min_confidence`, and\n`meta.defaults_applied` says when it came from the default.\n","schema":{"type":"number","minimum":0,"maximum":1,"default":0.7}},"PlaceMinConfidence":{"name":"min_confidence","in":"query","description":"Drop rows whose `confidence` is below this. **Defaults to `0.5`** for places (events,\nclasses and camps default to `0.7`); `0` disables the filter. The value used is echoed\nin `meta.applied_filters.min_confidence`.\n","schema":{"type":"number","minimum":0,"maximum":1,"default":0.5}},"Category":{"name":"category","in":"query","description":"Keep rows whose `categories` contain any of these. Repeatable.","style":"form","explode":true,"schema":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"}}},"Audience":{"name":"audience","in":"query","description":"Keep rows whose `audience` is one of these. Repeatable, and\n`?audience=teens,families` is the same thing. **The default excludes\n`adults`** — pass `audience=all`, or list `adults` explicitly, to\ninclude them. `not_adults` names the default itself (every listing\nexcept adult-only ones), so the value echoed in\n`meta.applied_filters.audience` can be sent back unchanged and returns\nthe same set. Detail routes have no such default: they return the\nitem regardless of audience. The audiences in effect are echoed in\n`meta.applied_filters.audience`. A listing flagged as adult-only\ncontent is in `adults` and in no other bucket, whatever audience\nwording its source page uses, so the default and `audience=kids` never\nreturn it and `audience=adults` always does.\n","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["kids","families","teens","adults","all_ages","all","not_adults"]}}},"Season":{"name":"season","in":"query","description":"Events, classes and camps only. Keep rows whose `traits.seasons`\ncontains any of these — meteorological seasons (by calendar month, in\nthe metro's local dates), not a source page's own wording. Repeatable,\nand `?season=summer,fall` is the same thing. Applied as a date-range\noverlap in the database, so paging stays exact; a class whose term is\n`ongoing`, or any row with no known date range, has `traits.seasons: []`\nand matches nothing here — pair with an explicit `from`/`to` if that\nmatters to the request.\n","style":"form","explode":true,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Season"}}},"Occasion":{"name":"occasion","in":"query","description":"Events and classes tagged for a seasonal occasion. A listing is tagged\naround that occasion's season. One value or a comma-separated list;\na list matches any value. Available on every plan.\n","schema":{"type":"string","description":"One or more comma-separated occasion values."},"example":"halloween,thanksgiving"},"Team":{"name":"team","in":"query","description":"Events built around a local pro sports team (watch parties, game-day\nthemed events, team or mascot appearances). One value or a\ncomma-separated list; a list matches any value. An unknown value is a\n`400` listing the allowed values. Events only: on a search it limits\nthe results to events. Available on every plan.\n","schema":{"type":"string","description":"One or more comma-separated team values."},"example":"eagles,phillies"},"Age":{"name":"age","in":"query","description":"A child's age in years. Keeps rows where `ages.min <= age <= ages.max`,\ntreating a missing bound as open: a row whose ages are not stated\n(`ages.min` and `ages.max` both `null`) is kept for every age, and a\nrow with only one bound is judged on that bound.\n","schema":{"type":"integer","minimum":0,"maximum":18}},"Neighborhood":{"name":"neighborhood","in":"query","description":"Neighborhood slug or free-text name (case-insensitive).","schema":{"type":"string","maxLength":100}},"Lat":{"name":"lat","in":"query","description":"Center latitude for a radius search. Requires `lng`.","schema":{"type":"number","minimum":-90,"maximum":90}},"Lng":{"name":"lng","in":"query","description":"Center longitude for a radius search. Requires `lat`.","schema":{"type":"number","minimum":-180,"maximum":180}},"ListRadiusM":{"name":"radius_m","in":"query","description":"Radius in metres around `lat`/`lng` (or `near_zip`, where enabled).\nRows without coordinates are excluded when a radius is given. The\ncircle is applied exactly, including when it crosses the\nantimeridian (a search at `lng=179.9` returns matching rows at\nnegative longitudes).\nA `page` walk under a radius is capped at 5,000 rows and returns\n`400` (`details.param: page`) past that; page with `cursor` instead,\nwhich has no such cap. An ordinary post-filter walk (e.g.\n`weekday=`) can still hit the cap.\n","schema":{"type":"integer","minimum":100,"maximum":80000,"default":5000}},"Zip":{"name":"zip","in":"query","x-stability":"beta","description":"**Beta — may not be enabled for all keys yet.** Keep rows whose postal ZIP or ZCTA\nmatches any of these, including rows without a geocoded point, so a row\nthat carries a ZIP but no geocoded point is still found. Repeatable,\nand `?zip=19147,19146` is the same thing. Exactly 5 digits; a leading\nzero is kept (`08053`, not `8053`). At most 25. Each matching item's\n`location.zip_source` says which column matched, `postal` or `zcta`.\n","style":"form","explode":true,"schema":{"type":"array","maxItems":25,"items":{"type":"string","pattern":"^\\d{5}$"}}},"NearZip":{"name":"near_zip","in":"query","x-stability":"beta","description":"**Beta — may not be enabled for all keys yet.** A radius search whose\norigin is the ZIP code's representative point rather than a\ncaller-supplied `lat`/`lng`. Pairs with `radius_m` (same bounds\nand default as the `lat`/`lng` form). An unrecognised ZIP is `400`\n(`details.reason: unknown_zip`); giving both `near_zip` and `lat`/`lng`\nis `400` — they are two different origins, and only one is read. The\nresolved point is echoed at `meta.geo.origin`.\n","schema":{"type":"string","pattern":"^\\d{5}$","examples":["19147"]}},"IncludeApproximate":{"name":"include_approximate","in":"query","x-stability":"beta","description":"**Beta — may not be enabled for all keys yet.** A spatial query (`lat`/`lng` or\n`near_zip`, both with `radius_m`) keeps only rows whose\n`geo_precision` is `rooftop`, `interpolated` or `street` by default —\na ZIP or place centroid reads as \"in range\" when it may not be.\n`true` also keeps `zip_centroid` and `place`. A row with no known\nprecision (`unknown`) is never in a spatial result either way; the\ncount of rows a spatial query dropped for missing or unusable\ncoordinates is `meta.geo.excluded_without_coordinates`. A row kept\nonly because of `true` here may have no coordinates of its own —\n`location.lat`/`lng` then carries an approximate point instead (see\nthe `Location` schema).\n","schema":{"type":"boolean","default":false}},"Free":{"name":"free","in":"query","description":"Events, classes, and camps only; ignored for places. `true` keeps only `price.is_free`; `false` keeps only priced rows.","schema":{"type":"boolean"}},"HasTime":{"name":"has_time","in":"query","description":"`true` keeps only events with a stated clock time.","schema":{"type":"boolean"}},"Recurring":{"name":"recurring","in":"query","description":"Filter on `is_recurring`.","schema":{"type":"boolean"}},"Occurrences":{"name":"occurrences","in":"query","description":"`expand` lists **one item per occurrence** instead of one per event: a\nrecurring series appears once for every occurrence that starts inside\n`[from, to]`, each with the same `id` and its own `occurrence` block;\na one-off event appears once, its `occurrence` built from its own\ntimes. Requires explicit `from` and `to`, at most 31 days inclusive,\nor the request is a `400`. Items are ordered by the occurrence's\n`starts_at`, then `id`; `limit` counts occurrences and `cursor` pages\nthrough them, including between occurrences of one series.\n\nOccurrences are computed in the metro's timezone, so local times hold\nacross daylight-saving changes, and they respect the series' end,\ncount and excluded dates. The filters that say *when* something\nhappens — `weekday`, `start_after`, `start_before`, `season` — apply\nto each occurrence; every other filter applies to the event. Events\nwith no date are not listed. `changed_since`, `q` and `facets` are not\navailable with `occurrences=expand`. Without this parameter `/events`\nbehaves exactly as before.\n","schema":{"type":"string","enum":["expand"]}},"Indoor":{"name":"indoor","in":"query","description":"Filter on `is_indoor`, a fact about the linked place. `true` keeps rows\nwhose place is stated to be indoors; `false` keeps rows whose place is\nstated not to be. A row whose `is_indoor` is `null` (unknown) matches\nneither, so `indoor=false` never means \"not known to be indoors\".\nOn a deployment that does not carry place traits yet this is `400` with\n`details.param: indoor`; retry without it.\n","schema":{"type":"boolean"}},"Outdoor":{"name":"outdoor","in":"query","description":"Filter on `is_outdoor`, a fact about the linked place. Same rules as\n`indoor`: unknown (`null`) matches neither value.\n","schema":{"type":"boolean"}},"Sensory":{"name":"sensory","in":"query","description":"Filter on `is_sensory_friendly` (on events and classes, the linked\nplace's; on places, the place's own). Same rules as `indoor`: unknown\n(`null`) matches neither value. Places usually state this only when it\nis true, so `sensory=false` matches few rows.\n","schema":{"type":"boolean"}},"ChangedSince":{"name":"changed_since","in":"query","description":"Sync mode. Return rows with `updated_at` strictly after this instant, ordered by `updated_at, id`;\npage with `cursor`. Because an edit can only move `updated_at` forward, a sync traversal is\n**at least once**: a row edited while you page may be delivered twice, but is never skipped.\nSync cursors do not expire. Removed rows are not returned here — use `/v1/changes`.\n","schema":{"type":"string","format":"date-time"}},"Q":{"name":"q","in":"query","description":"Full-text search over the listing's name and search text\n(websearch syntax: `storytime park`, `\"drop in\"`,\n`art -camp`). A **filter, not a ranking**: results keep the\ncollection's own order (start, name). Very broad queries may be\ncapped; when they are, `meta.search.capped` is true. Add filters or a\nmore specific `q` to narrow the results. `q` also matches the\norganizer's name and the place's name, ignoring spacing and\npunctuation and tolerating small typos (`design gym` finds\n`designgym.co`). At most 200 characters. The cursor is bound to the\nquery text.\n","schema":{"type":"string","maxLength":200}},"Weekday":{"name":"weekday","in":"query","description":"Keep rows on **any** of these local days. On `/events` it is the\nweekday of `starts_local`, bounded by the date window (with\n`occurrences=expand`, and on `/events/calendar`, the weekday of each\noccurrence); on `/classes`\nit is `schedule_days && [...]` — meets on any of them — beside\n`schedule_day`, which means \"meets on this one\". Repeatable, and\n`?weekday=saturday,sunday` is the same thing. Ignored on `/camps`.\n","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}}},"StartAfter":{"name":"start_after","in":"query","description":"Local start time at or after this, `HH:MM` (or `HH:MM:SS`). On\n`/events` the column is `null` whenever `has_time` is `false`, so a\nbound implies a known time; on `/classes` it is the weekly\n`schedule.start_time`.\n","schema":{"type":"string","pattern":"^\\d{2}:\\d{2}(:\\d{2})?$","examples":["09:00"]}},"StartBefore":{"name":"start_before","in":"query","description":"Local start time strictly before this, `HH:MM`; `09:00`–`12:00` is the morning and `12:00` belongs to the afternoon. Must be after `start_after` when both are given.","schema":{"type":"string","pattern":"^\\d{2}:\\d{2}(:\\d{2})?$","examples":["12:00"]}},"MaxPrice":{"name":"max_price","in":"query","description":"A budget. Keeps free rows and rows whose lowest stated price is at\nmost this; a row that states only a maximum is judged on that. A row\nwith no price at all is not \"under N\" and is dropped — pass `free=false`\nwith no `max_price` to see priced-but-unstated rows. Not a `/places`\nfilter (admission lives under `admission.child_price`).\n","schema":{"type":"number","minimum":0,"maximum":100000}},"Ids":{"name":"ids","in":"query","description":"Fetch specific listings of this resource type in one call: up to 100\ncomma-separated listing UUIDs (`ids=<id>,<id>`). With `ids`, the default\ndate window does not apply, and the other filters and `limit` are ignored;\n`fields`, `expand` and `include` still shape each item. Rows come back in\nthe order given, repeated ids once. An id that is unknown, belongs to a\ndifferent resource type or metro, or is no longer active is listed in\n`meta.missing_ids` instead of failing the call. There is no paging:\n`has_more` is `false` and `next_cursor` is `null`. A malformed id, more\nthan 100 ids, or `ids` together with `cursor` or `page` is `400`.\n","schema":{"type":"string","example":"2f3c9d4e-3d2b-4b7d-9a3e-1b2c3d4e5f60,5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"}},"StartsFrom":{"name":"starts_from","in":"query","description":"Classes only. Keep classes whose term **starts** on or after this local date\n(`YYYY-MM-DD`, metro timezone, inclusive). Unlike `from`/`to`, which match a class\nthat is running at any point in the window, this matches the start date itself,\nso `starts_from` and `starts_to` together answer \"classes starting this week\".\nEither bound may be used alone. A class with no start date never matches. For a\nprogram with `sections`, it matches when any one section starts in the range and\nthe program's own start date is not consulted; the returned `sections` are not\ntrimmed, so read each section's `term.starts_on` to see which one matched. It\ncombines with every other filter, and the default `from` (today) window still\napplies, so pass an earlier `from` to include classes that started and ended\nbefore today. The values used are echoed in `meta.applied_filters`.\n","schema":{"type":"string","format":"date"}},"StartsTo":{"name":"starts_to","in":"query","description":"Classes only. Keep classes whose term starts on or before this local date\n(inclusive); see `starts_from`. Must not be before `starts_from`, and at most 366\ndays after it when both are given; otherwise `400` with `details.param`.\n","schema":{"type":"string","format":"date"}},"OrganizationId":{"name":"organization_id","in":"query","description":"Keep rows published by this organization (`organization.id`). Pair with `/v1/{metro}/organizations` to find the id.","schema":{"type":"string","format":"uuid"}},"Fields":{"name":"fields","in":"query","description":"Keep only these dotted paths on each item (`name,place.name,price.is_free`);\n`id` and `type` are always kept so a trimmed item stays addressable.\nA top-level name the resource does not have is `400` with the\nresource's names in `details.allowed`. Shapes the response only —\nthe result set and the cursor are unaffected, so a traversal may add\nor drop it between pages. At most 50 paths.\n","style":"form","explode":false,"schema":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*$","maxLength":64}}},"Openings":{"name":"openings","in":"query","description":"Classes only. `true` keeps programs that have open seats in one of their sections, and that\nsection must also meet every other filter you send (day, age, time, dates, price). A program\nwithout sections is judged on its own registration status. `false` is the same as leaving it out.\n","schema":{"type":"boolean"}},"Expand":{"name":"expand","in":"query","description":"Attach the full `Place` and/or the `Organization` behind each item under\n`expanded`, one extra read per expansion per page (not per row). The\nreference objects `place` and `organization` are unchanged. An expanded\nplace is the same object `/v1/places/{id}` serves and is **not**\nfiltered by `min_confidence` — it is context for a row that already\npassed. `place` needs the `place` type scope (`403` otherwise).\n`fields=` may name `expanded.place.name`.\n\n`sessions` applies to classes only (elsewhere it does nothing): by default a class list shows\none card for a program that is published as several listings, with the others under the\ncard's `sessions`; `expand=sessions` returns every class on its own instead. A cursor is\nonly valid with the same `expand=sessions` setting it was issued under.\n","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["place","organization","sessions"]}}},"Include":{"name":"include","in":"query","description":"Opt into a block the lean default response leaves out.\n\n`source` (`Source` schema): `url`, `crawled_at`, and a nested\n`verification` object (`status`, `basis`, `date_basis`), attached\nunder the item's own `source` key. `fields=` and `expand=` both\nstill apply — `fields=source.verification.basis` works, and expansion\nis unaffected. A paid add-on, entitled per key. Not entitled: `403`\nwith `error.code: include_not_permitted` — unless `include_mode=lenient`,\nwhich instead answers `200` without the block and adds a\n`notices[]` entry naming it.\n\n`forecast` (`Forecast` schema): a short event-window outlook in US\nunits. It is available only for timed US events with coordinates that\nstart within the next seven days. Ineligible events omit the key.\nAvailability failures also omit it and add `forecast_unavailable` to\ntop-level `notices[]`. This paid add-on has the same entitlement rules\nas `source`.\n\n`related` (`Related` schema): the rows a listing page shows beside\nthe listing, in the same response. Available only when reading a\nsingle event, class or camp by id or slug; on a list, a search or a\nplace it is `400`. It carries `similar` (nearby listings of the same\nkind, for children of overlapping ages, in the same Monday-to-Sunday\nweek as this listing's date), `from_organization` (the organization's\nnext upcoming listings of the same type, one per series) and\n`at_place` (other listings at the same place in the same week), each\nat most six cards. Cards follow what the list endpoints would return\nto the same key: anything a list hides is never a related card. If a\nlist cannot be produced it comes back empty and `notices[]` carries\n`related_unavailable`. Entitled like `source`, except that a `*` grant\ndoes not cover it: name it in the key's features.\n\nAn unrecognized value is `400`, the same as any other unknown enum\nmember.\n","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["source","forecast","related"]}}},"IncludeMode":{"name":"include_mode","in":"query","description":"How an `include=` the key is not entitled to is handled. `strict`\n(default): `403 include_not_permitted`. `lenient`: `200` with the\nblock left off and a `notices[]` entry describing what was omitted\nand why. Has no effect without `include=`, and no effect on an\n`include=` the key *is* entitled to.\n","schema":{"type":"string","enum":["strict","lenient"],"default":"strict"}},"DirectoryQ":{"name":"q","in":"query","description":"Find a business by what a person would type: its name, its website\naddress or a pasted URL. Casing, punctuation, spacing and endings such\nas `LLC`, `Inc`, `.com` and `& Co` are ignored, `design gym` finds\n`designgym`, and a small typo still finds it. On `organizations`,\nresults are ranked by `score` and carry `match`; on `neighborhoods`,\na case-insensitive substring of the name. At most 100 characters.\n","schema":{"type":"string","maxLength":100}},"DirectoryType":{"name":"type","in":"query","description":"Exact match on the organization's type.","schema":{"type":"string","pattern":"^[a-z0-9_]+$"}},"VersionsCursor":{"name":"cursor","in":"query","description":"The last `version_id` seen (`meta.next_cursor`); the page continues with older versions (`id < cursor`). A bare integer, not an opaque cursor.","schema":{"type":"string","pattern":"^\\d{1,18}$"}},"ChangesCursor":{"name":"cursor","in":"query","description":"This is not an opaque cursor: pass back the decimal string returned by\n`meta.next_cursor`, and the feed resumes strictly after it.\n\nIt is not bound to `since`, `metro`, `type` or `limit`, so you may\nchange any of those between pages. It can be persisted indefinitely\nas a durable position in the feed.\n\nA value that is not 1-18 digits returns `400` with\n`details.param: cursor`.\n","schema":{"type":"string","pattern":"^\\d{1,18}$"},"example":"18231"},"Cursor":{"name":"cursor","in":"query","description":"Opaque cursor from `meta.next_cursor`. Mutually exclusive with `page`.\n\nA cursor is **bound to the request that issued it**: route, resource, metro, mode, and the whole\nfilter set (`from`/`to` included, even when defaulted — `limit` excluded, so page size may change).\nPresenting it to any other request, hand-crafting one, or altering its contents is `400` with\n`details.param: cursor`.\n\n**Browse cursors are best effort.** Browse orders on mutable fields (`starts_at`,\n`sort_date`, `name`), so a row edited between two pages may be skipped or\nreturned twice; inserts and deletes are safe. For a traversal that must not lose rows, use\n`changed_since` (at least once); for an exact, ordered feed that also reports\nremovals, use `/v1/changes`. See [Pagination](/playground/guide/pagination).\n\n**A cursor is deterministic**, and does not expire on a clock. The same page of the same\nquery always encodes to the same string, which is what lets the response carry a stable\n`ETag`: re-requesting a page you already hold costs a `304`, not a body. A browse cursor on\na *default* date window stops being valid when that window moves, because `from` defaults to\ntoday in the metro and the resolved date is part of what the cursor is bound to — that is a\n`400` naming the binding, and the answer is to start the traversal again.\n","schema":{"type":"string"}},"Page":{"name":"page","in":"query","description":"1-based page number (browse mode). Best effort under concurrent edits, as `cursor` describes.","schema":{"type":"integer","minimum":1,"default":1}},"Limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"ListLimit":{"name":"limit","in":"query","description":"Items per page, 1 to 200. **`0` is accepted only together with `facets`**: the\nresponse then carries the facet counts and an empty `data`, with no page read.\n","schema":{"type":"integer","minimum":0,"maximum":200,"default":50}},"Facets":{"name":"facets","in":"query","description":"Counts over **every listing that matches the filters**, not just this page, returned\nas a top-level `facets` object beside `data` and `meta`. Comma-separated or repeated:\n`category`, `weekday`, `time_block`, `price_band`, `age_band`, `organization`. Each\nlisting is counted in every bucket it belongs to, so `category`, `age_band` and a\nclass's `weekday` can sum to more than `facets.total`; a listing that states nothing\nfor a facet is counted under `unspecified`. A facet the collection has no data for\n(`weekday` on camps and places, for example) is named in `facets.unavailable`.\n\nAvailable on every plan, and the request counts as one request however large the\nset: a facets-only call (`limit=0`) is the cheap way to size a market before, or\ninstead of, paging it. `page` and `cursor` do not affect the counts. The number of\norganizations listed is capped; very large sets are counted up to a fixed bound, and\n`facets.is_complete` is `false` when a count covers only part of the set.\n","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["category","weekday","time_block","price_band","age_band","organization"]}}},"PointLat":{"name":"lat","in":"query","description":"Latitude of the point to score. Requires `lng`; mutually exclusive with `address`.","schema":{"type":"number","minimum":-90,"maximum":90}},"PointLng":{"name":"lng","in":"query","description":"Longitude of the point to score. Requires `lat`; mutually exclusive with `address`.","schema":{"type":"number","minimum":-180,"maximum":180}},"NearbyLat":{"name":"lat","in":"query","required":true,"description":"Latitude of the point to search around.","schema":{"type":"number","minimum":-90,"maximum":90}},"NearbyLng":{"name":"lng","in":"query","required":true,"description":"Longitude of the point to search around.","schema":{"type":"number","minimum":-180,"maximum":180}},"Address":{"name":"address","in":"query","description":"A street address to resolve server-side instead of sending a point.\nBiased to the metro. Resolution is subject to the key's usage limits;\n`429` includes `Retry-After` when capacity is unavailable.\n","schema":{"type":"string","maxLength":300}},"RadiusM":{"name":"radius_m","in":"query","description":"Radius in metres. 1600 is about a mile — walking distance for a family.","schema":{"type":"integer","minimum":100,"maximum":16000,"default":1600}},"Days":{"name":"days","in":"query","description":"How far ahead the event window reaches, in days.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},"NearbyTypes":{"name":"types","in":"query","description":"Restrict to these listing types. Repeatable, or comma-separated. Each must be in the key's `scopes.types`. Defaults to all four.","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["event","class","camp","place"]}}},"NearbyCursor":{"name":"cursor","in":"query","description":"`meta.next_cursor` from the previous page: `\"<distance_m>:<listing_id>\"`. There is no `page` on this route.","schema":{"type":"string","pattern":"^\\d+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"}},"AroundRadiusM":{"name":"radius_m","in":"query","description":"Radius in metres. 1600 is about a mile — walking distance for a family. Capped lower than `/activity` and `/nearby` (8000 rather than 16000): past a few miles \"around this address\" stops being a neighbourhood.","schema":{"type":"integer","minimum":100,"maximum":8000,"default":1600}},"AroundAges":{"name":"ages","in":"query","description":"Age bands to favour. Repeatable, or comma-separated. A **soft** filter: rows that state no age band at all are kept because unknown is not the same as \"not for your child\".","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["baby","toddler","young_kids","bigger_kids"]}}},"AroundTypes":{"name":"types","in":"query","description":"Restrict to these listing types. Repeatable, or comma-separated. Each must be in the key's `scopes.types`; with none given, the key's own scope decides. Dateless `ongoing` listings are not a value here — they ride with `place` and land in the `places` group.","style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["event","class","camp","place"]}}},"AroundMinConfidence":{"name":"min_confidence","in":"query","description":"Minimum row confidence. The default is shown in the schema; collection endpoints may use different defaults.","schema":{"type":"number","minimum":0,"maximum":1,"default":0.5}},"AroundLimit":{"name":"limit","in":"query","description":"Maximum items **per group**, not per response.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}},"AroundCursor":{"name":"cursor","in":"query","description":"A group's `next_cursor` from the previous response: `\"<group>:<offset>\"`. Passing it returns that one group's next page; `meta.cursor_group` names it. There is no `page` on this route.","schema":{"type":"string","pattern":"^(happening_soon|recurring_programs|classes_enrolling|camps|places):\\d{1,6}$"}}},"responses":{"BadRequest":{"description":"Malformed or contradictory parameters (`lat` without `lng`, `to` before `from`, unknown `category`),\nor a `cursor` this API did not issue for this exact request — replayed from another endpoint, resource,\nmetro or filter set, hand-crafted, or altered.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"default":{"summary":"400 error","value":{"error":{"code":"bad_request","message":"radius_m: must be at least 100","details":{"param":"radius_m"},"request_id":"req_dfbc3295a8382b05"}}}}}}},"Unauthorized":{"description":"Missing, unknown or revoked `X-API-Key`. Also returned when the key record itself does not\nvalidate — the server fails closed and logs why rather than assuming anything about a row it\ncannot vouch for, and when the value is not shaped like a key (`tl_` + 8 hex + `_` + 48 hex).\nThe message is `invalid API key`; the reason is not\ndisclosed. The one exception is a credential shaped like a different\nkind of token, whose 401 explains it is the wrong credential for\n`/v1` rather than repeating the generic message.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"default":{"summary":"401 error","value":{"error":{"code":"unauthorized","message":"missing X-API-Key header","request_id":"req_90e63908273f6bff"}}}}}}},"Forbidden":{"description":"Two different reasons share this status. **Read `error.code`.**\n\n`forbidden` — the key is valid but its `scopes` exclude this metro or\nresource type, or the client is inactive. Returned when the caller\n**named** the metro or type it was refused — in the path, or in\n`?metro=`. Where the caller supplied only an identifier, an\nout-of-scope resource is a `404` instead; see NotFound.\n\n`include_not_permitted` (endpoints that take `include=` only) — the\nkey is valid and in scope, but is not entitled to a requested\n`include=` add-on (`details.include` names it). Add\n`include_mode=lenient` to get a `200` without the block instead of\nthis. See [Shaping responses](/playground/guide/shaping-responses).\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"scope":{"summary":"403 error — scope","value":{"error":{"code":"forbidden","message":"key is not scoped to metro 'boston'","details":{"metros":["philadelphia"]},"request_id":"req_9e7a750acef48ab2"}}},"include_not_permitted":{"summary":"403 error — include not permitted","value":{"error":{"code":"include_not_permitted","message":"include=source is not available on this key's plan; retry without it, or add include_mode=lenient","details":{"include":"source"},"request_id":"req_2c6a19f8d0b34e77"}}}}}}},"NotFound":{"description":"No published, active resource with that id (or unknown metro).\n\nAlso returned when the resource exists but sits in a metro outside the\nkey's `scopes.metros`, on the routes that take an **identifier** rather\nthan a metro: `/v1/{type}/{id}`, `/v1/{type}/slug/{slug}` and\n`/v1/organizations/{id}`. The metro there is discovered from the row, not\nnamed by the caller, so a `403` would confirm that a guessed id or slug\nis real and say which metro it is in. The two cases are deliberately\nindistinguishable — same code, same message, same absent `details`.\n\nNaming the metro is a different question and still gets the explicit\n`403` with the key's own scopes: `/v1/boston/events`, or `?metro=boston`\non a slug lookup.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"default":{"summary":"404 error","value":{"error":{"code":"not_found","message":"unknown metro 'boston'","request_id":"req_7431b51e10ec2b77"}}}}}}},"MethodNotAllowed":{"description":"The path exists; the method does not. Every route on this API is a\nread, so `Allow` is always `GET, HEAD, OPTIONS`. A method on a path\nthat does **not** exist is a `404` instead — `405` is only ever sent\nwhere there is a target resource to refuse.\n","headers":{"Allow":{"$ref":"#/components/headers/Allow"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"method_not_allowed","message":"POST is not allowed on this path; this API is read-only","details":{"allow":["GET","HEAD","OPTIONS"]},"request_id":"req_01J9Z3"}}}}},"TooManyRequests":{"description":"A limit was reached. **Branch on `error.code`, not on the status** — two\ndifferent limits share this status:\n\n* `rate_limited` — the per-minute rate. `Retry-After` is seconds, and\n  retrying after it succeeds.\n* `rate_limited` can also mean address lookups are temporarily\n  unavailable. The response explains the condition and provides\n  `Retry-After`; callers that already have coordinates can send\n  `lat`/`lng` instead.\n* `quota_exceeded` — the monthly allowance, or a client's hard cap.\n  `Retry-After` points at the start of the next UTC month and can\n  therefore be very large; `details` carries `plan`, `monthly_limit`,\n  `used` and `resets_at`. Backing off will not help before the reset —\n  the plan has to change. This is a `429`; `402` is reserved.\n","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-Quota-Limit":{"$ref":"#/components/headers/X-Quota-Limit"},"X-Quota-Remaining":{"$ref":"#/components/headers/X-Quota-Remaining"},"X-Quota-Reset":{"$ref":"#/components/headers/X-Quota-Reset"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"default":{"summary":"429 error","value":{"error":{"code":"rate_limited","message":"3 requests per minute exceeded","request_id":"req_06bfd3c2d5e8aa9f"}}}}}}},"InternalError":{"description":"A bug on our side. The message is always the constant `internal error`;\ndetails are never included in the body. Retry once with backoff,\nthen contact support with the `request_id`.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal","message":"internal error","request_id":"req_01J9Z3"}}}}},"NotImplemented":{"description":"This endpoint or feature is not available and will not become\navailable without a configuration change — for `?address=`, this\nmeans no geocoder is configured.\n\nNothing is failing, so **do not retry and do not back off**: there\nis no `Retry-After`, and the answer will not change inside any\ntimeout you set. Treat the feature as switched off, disable it in\nyour UI, and use the alternative the message names where there is\none (`lat`/`lng` instead of `address`).\n\nThe message is a constant per endpoint family and names no internal\nobject. Include the `request_id` when contacting support.\n","headers":{"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"projection":{"summary":"This endpoint is not enabled","value":{"error":{"code":"not_implemented","message":"this endpoint is not enabled on this deployment; it is not a fault and retrying will not help","request_id":"req_01J9Z3"}}},"geocoder":{"summary":"No geocoder configured, so `?address=` cannot work here","value":{"error":{"code":"not_implemented","message":"address lookup is not enabled on this deployment; send lat and lng instead","request_id":"req_01J9Z3"}}}}}}},"ServiceUnavailable":{"description":"A **transient** outage: a dependency could not be reached or did not\nanswer in time. This is the 5xx worth retrying — `Retry-After` says\nhow long, and the same request is expected to succeed afterwards.\n\nLike every other error here, the message names no internal detail.\n","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-Request-Id":{"$ref":"#/components/headers/X-Request-Id"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unavailable","message":"the service is temporarily unable to serve this request; retry after the interval in Retry-After","request_id":"req_01J9Z3"}}}}}},"schemas":{"ListingType":{"type":"string","enum":["event","class","camp","place","ongoing"],"description":"The listing's type. `ongoing` rows are served only on `/v1/changes` today."},"ListingStatus":{"type":"string","enum":["published","archived"],"description":"Lists and the default detail read return\n`published` only; `archived` appears only under\n`include_archived=true`, and is what a consumer renders a \"this has\npassed\" banner from. `draft` is never served.\n"},"ListingCategory":{"type":"string","enum":["arts_creative","music_movement","sports_active_play","nature_outdoors","storytime_books","stem_learning","cooking_food","social_play_spaces"],"description":"The listing-category taxonomy."},"PriceType":{"type":["string","null"],"enum":["free","fixed","range","variable",null],"description":"An explicit amount beats the word \"free\" when they disagree. Some older rows carry `variable` where newer rows use `range` for a non-fixed amount."},"PriceScope":{"type":["string","null"],"enum":["admission","free_admission_paid_extras","members_free","age_free","per_item",null],"description":"What the amounts refer to. May be `null` on older rows."},"DateConfidence":{"type":["string","null"],"enum":["stated","inferred","unevidenced","unknown",null],"description":"How the listing's date was established: `stated` (the source page\ngave it directly), `inferred` (derived, e.g. from a recurrence rule),\n`unevidenced` (present but not traceable to a source statement), or\n`unknown` (not yet classified). `null` on older rows scored before\nthis field existed.\n"},"Audience":{"type":["string","null"],"enum":["kids","family","teens","adults","seniors","private",null],"description":"Audience the source page states. A listing flagged as adult-only content reads `adults` here whatever the page says, matching the top-level `audience`. Adult/senior/private rows are normally not published; the value is exposed so consumers can double-check."},"ListingAudience":{"type":"string","enum":["kids","families","teens","adults","all_ages"],"description":"Who the listing is for, derived from a suitability check we run on\nthe listing (not the source page's own wording) and refined by\n`ages`: `adult_only` reads `adults`; `mixed` reads `all_ages`;\n`kid_friendly`/`young_kids`/`bigger_kids` become `teens` when\n`ages.audience` says `teens` or `ages.max` is 13 or older, `families`\nwhen `ages.audience` says `family`, else `kids`. Always present.\nA listing flagged as adult-only content always reads `adults`,\nwhatever audience wording its source page uses.\nFilter with `audience=`; the default excludes `adults`.\n"},"Occasion":{"type":"string","enum":["halloween","thanksgiving","winter_holidays","new_year","lunar_new_year","valentines","st_patricks","easter","juneteenth","july_4th","back_to_school","summer_break"]},"Team":{"type":"string","description":"A local pro sports team an event is built around.","enum":["eagles","phillies","sixers","flyers","union"]},"Season":{"type":"string","enum":["spring","summer","fall","winter"],"description":"Meteorological season (by calendar month, in the metro's local dates), Northern Hemisphere."},"Traits":{"type":"object","description":"Events, classes and camps only.","properties":{"seasons":{"type":"array","items":{"$ref":"#/components/schemas/Season"},"description":"Every season the listing's own date range touches — a multi-day\nevent or a term can carry more than one. Events: `starts_local`/\n`ends_local`. Classes: the term's `starts_on`/`ends_on`; an\n`ongoing` or dateless term is `[]`. Camps: the camp's own `season`\ncolumn when stated, else its span dates. Filter with `season=`.\n"}}},"PlaceTypeHint":{"type":"string","description":"Served as `type_hint`.","enum":["play_space","museum","park","library","theater","sports_facility","farm","restaurant","other"]},"RegistrationStatus":{"type":"string","enum":["open","closed","waitlist","coming_soon"]},"SourceStatus":{"type":["string","null"],"description":"The outcome of the last check against the source page, `null` before\nthe listing has been checked. `flagged` means a specific audience or\ncontent problem was found, backed by evidence — a real, reachable\noutcome, just an uncommon one. `unverifiable` means the check could\nnot confirm the listing either way. Treat any other string as\nunknown, not as one of these.\n","enum":["clear","changed","flagged","unverifiable","unreachable","gone",null]},"ConfidenceBasis":{"type":"string","enum":["verified","baseline"],"description":"Who produced `confidence`. `verified` once the listing has been verified, else the documented baseline. Part of `source.verification` (`include=source`)."},"ChangeKind":{"type":"string","enum":["created","updated","date_changed","price_changed","location_changed","archived","restored"]},"Metro":{"type":"object","required":["slug","name","timezone"],"properties":{"slug":{"type":"string","examples":["philadelphia"]},"name":{"type":"string","examples":["Philadelphia Area"]},"timezone":{"type":"string","description":"IANA zone used for `starts_local`.","examples":["America/New_York"]},"aliases":{"type":"array","items":{"type":"string"},"description":"**Informational only.** Other names this metro is known by, for\ndisplay and for matching user input on your side. Paths and\n`?metro=` accept the `slug` and nothing else: `/v1/philly/events`\nis `404`, not a redirect to `/v1/philadelphia/events`. Resolve an\nalias to a `slug` against this list before you build a URL.\n","examples":[["philly","phl","philadelphia pa"]]},"is_active":{"type":"boolean"}}},"PlaceRef":{"type":"object","description":"The place a listing is held at — the linked place listing when one exists. The row's own address is `location`.","required":["id","slug","name"],"properties":{"id":{"type":["string","null"],"format":"uuid","description":"The linked place's id (a published place) or null."},"slug":{"type":["string","null"],"description":"The linked place's slug; `/v1/places/slug/{slug}` resolves it."},"name":{"type":["string","null"],"description":"Linked place's name. Null when unlinked — the address line often still names the place."}}},"Location":{"type":"object","description":"Where the row itself is — its own geocoded address, coordinates and neighborhood — whether or not it is linked to a place.","properties":{"address":{"type":["string","null"]},"street_address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zip":{"type":["string","null"]},"lat":{"type":["number","null"],"description":"The listing's own geocoded latitude, or — when beta geo filters are enabled and the listing has none of its own — an approximate point instead. Whichever it is, `geo_precision` on this same object says how much to trust it."},"lng":{"type":["number","null"],"description":"See `lat`."},"neighborhood":{"type":["string","null"]},"neighborhood_slug":{"type":["string","null"],"description":"What `neighborhood=` takes."},"geo_precision":{"type":["string","null"],"description":"**Present only when beta geo filters are enabled**; otherwise the key is\nabsent, not null. `rooftop` | `interpolated` | `street` | `place`\n| `zip_centroid` | `unknown` | `null` (never geocoded). Null when\nthe flag is off or the row carries none.\n"},"geo_source":{"type":["string","null"],"description":"**Present only when beta geo filters are enabled.** The source category for the resolved coordinates, or null."},"zip_source":{"type":["string","null"],"description":"**Present only when `zip=` was given and beta geo filters are enabled.**\nWhich postal-code representation matched this row.\n"}}},"Price":{"type":"object","properties":{"type":{"$ref":"#/components/schemas/PriceType"},"min":{"type":["number","null"],"description":"Minimum price."},"max":{"type":["number","null"],"description":"Maximum price."},"scope":{"$ref":"#/components/schemas/PriceScope"},"note":{"type":["string","null"],"description":"Verbatim price wording."},"unit":{"type":["string","null"],"description":"One of `per_child`, `per_session` when stated."},"is_free":{"type":"boolean","description":"True when the stated price type is free, or — absent a stated price — when the source itself marked the listing free."},"currency":{"type":"string","const":"USD","description":"All listing prices are decimal dollars, never cents."}}},"Ages":{"type":"object","properties":{"min":{"type":["integer","null"],"description":"Minimum age, in years. `null` means the source does not state\none; `0` is only reported when the listing states it (with a\nmaximum or age wording, e.g. 0–5), never as a stand-in for\n\"not stated\".\n"},"max":{"type":["integer","null"],"description":"Maximum age, in years."},"text":{"type":["string","null"],"description":"Verbatim age wording. Populated for classes; null for events and camps today."},"audience":{"$ref":"#/components/schemas/Audience"},"bands":{"type":["array","null"],"items":{"type":"string"},"description":"Derived age bands."}}},"ConfidenceScore":{"type":"number","minimum":0,"maximum":1,"description":"Trust score. The same number `min_confidence` filters on — the\nscore once the listing has been verified, else the documented\nbaseline. A flat field, not a nested object, to keep the default\npayload small; detail is behind `include=source`.\n"},"Source":{"type":"object","description":"Where the listing's data came from, and how it was verified —\neverything the lean default response leaves out. Present only with\n`include=source`, a paid add-on: `403` with\n`error.code: include_not_permitted` when the key is not entitled, or\n(`include_mode=lenient`) a `200` without this block plus a\n`notices[]` entry. See [Shaping responses](/playground/guide/shaping-responses).\n","required":["url","crawled_at","verification"],"properties":{"url":{"type":["string","null"],"format":"uri","description":"The page the listing was parsed from."},"crawled_at":{"type":["string","null"],"format":"date-time","description":"When that page was last fetched."},"verification":{"type":"object","description":"How this listing was verified.","required":["status","basis","date_basis"],"properties":{"status":{"$ref":"#/components/schemas/SourceStatus"},"basis":{"$ref":"#/components/schemas/ConfidenceBasis"},"date_basis":{"$ref":"#/components/schemas/DateConfidence"}}}}},"OrganizationRef":{"type":"object","properties":{"id":{"type":["string","null"],"format":"uuid","description":"The linked organization's id, or null."},"name":{"type":["string","null"]},"slug":{"type":["string","null"]}}},"Organization":{"type":"object","required":["id","name","links"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":["string","null"]},"organization_type":{"type":["string","null"],"description":"The organization's type, as the source states it."},"website_url":{"type":["string","null"],"format":"uri"},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"is_verified":{"type":["boolean","null"],"description":"Whether the organization's claim to this profile has been editorially verified — unrelated to listing data verification."},"metros":{"type":"array","items":{"type":"string"},"description":"Slugs of metros where the organization has live listings."},"links":{"$ref":"#/components/schemas/OrganizationLinks"}}},"AppliedFilters":{"type":"object","description":"The filters this response was actually computed with, as their request parameters:\nthe value in effect for each filter the endpoint applies, whether you sent it or it\ncame from a default. A filter that is unset (no `category=`, for instance) is absent,\nand a filter the endpoint does not apply (`weekday` on camps) is never listed.\nAlways present: `min_confidence` and `audience`, plus `from` and `to` on events,\nclasses and camps (`to` is `null` where the window is open-ended). The exception is\na batch read by `ids=`: no window or filters apply, so only `ids` is listed.\n`meta.defaults_applied` names which of these came from a default.\n","properties":{"from":{"type":"string","format":"date"},"to":{"type":["string","null"],"format":"date"},"min_confidence":{"type":"number"},"audience":{"type":"array","description":"The audience filter in effect, in a form you can send back as `audience=` to get\nthe same set. With no `audience=` given this is `[\"not_adults\"]`: every listing\nexcept adult-only ones. `audience=all` is echoed as `[\"all\"]`. A list you named\nis echoed as given.\n","items":{"type":"string","enum":["kids","families","teens","adults","all_ages","all","not_adults"]}},"radius_m":{"type":"integer","description":"Present on a radius search."},"ids":{"type":"array","description":"Present on a batch read by `ids=`, as the de-duplicated ids requested.","items":{"type":"string","format":"uuid"}}},"additionalProperties":true},"DefaultsApplied":{"type":"array","description":"The names in `applied_filters` whose value came from a default rather than your\nrequest, for example `[\"from\", \"to\", \"min_confidence\", \"audience\"]`. Empty when you\nnamed every filter that has a default. A default that narrows a result (the 30-day\nevent window, the confidence floor, the adult-audience exclusion) is listed here so\na smaller-than-expected set can be explained from the response alone.\n","items":{"type":"string"}},"FacetCount":{"type":"object","required":["value","count"],"properties":{"value":{"type":"string","description":"The bucket. `unspecified` counts listings that state nothing for this facet."},"count":{"type":"integer"}}},"OrganizationFacet":{"type":"object","required":["distinct","top","other_count","unspecified_count"],"properties":{"distinct":{"type":"integer","description":"Organizations with at least one listing in the set."},"top":{"type":"array","description":"The organizations with the most listings, most first; capped at 20.","items":{"type":"object","required":["id","name","count"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"count":{"type":"integer"}}}},"other_count":{"type":"integer","description":"Listings whose organization is not in `top`."},"unspecified_count":{"type":"integer","description":"Listings with no organization."}}},"Facets":{"type":"object","description":"Counts over the whole filtered set. Buckets: `weekday` is monday..sunday (an event's\nlocal day, or every day a class meets); `time_block` is `morning` (before 12:00),\n`afternoon` (12:00 to before 17:00) and `evening` (17:00 on), from the local start\ntime; `price_band` is `free` (exactly the listings `free=true` returns), then `under_20`,\n`20_to_50`, `50_to_100` and `100_plus` from the lowest stated price in US dollars, with\na listing that is not free and states no price above zero counted as `unspecified`; `age_band` is the same `baby`, `toddler`,\n`young_kids`, `bigger_kids` bands as `ages.bands`. Enumerated facets list every\nbucket, including zeros; `category` lists the buckets that occur, most first.\n","required":["total","is_complete"],"properties":{"total":{"type":"integer","description":"Listings the facets were counted over."},"is_complete":{"type":"boolean","description":"`false` when the set was too large to count in full, or counting ran out of\ntime; the counts then cover part of it. Narrow the filters and ask again.\n"},"unavailable":{"type":"array","description":"Requested facets this collection has no data for.","items":{"type":"string"}},"category":{"type":"array","items":{"$ref":"#/components/schemas/FacetCount"}},"weekday":{"type":"array","items":{"$ref":"#/components/schemas/FacetCount"}},"time_block":{"type":"array","items":{"$ref":"#/components/schemas/FacetCount"}},"price_band":{"type":"array","items":{"$ref":"#/components/schemas/FacetCount"}},"age_band":{"type":"array","items":{"$ref":"#/components/schemas/FacetCount"}},"organization":{"$ref":"#/components/schemas/OrganizationFacet"}}},"ListMeta":{"type":"object","required":["limit","count","has_more","applied_filters","defaults_applied"],"properties":{"applied_filters":{"$ref":"#/components/schemas/AppliedFilters"},"defaults_applied":{"$ref":"#/components/schemas/DefaultsApplied"},"metro":{"type":["string","null"]},"page":{"type":["integer","null"],"description":"Present in browse mode."},"limit":{"type":"integer"},"count":{"type":"integer","description":"Items in this page."},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to fetch the next page (sync mode, or browse mode beyond page 1). Valid only for this exact request — same route, resource, metro, mode and filters. It does not expire on a clock, which is what lets a paged list keep a stable `ETag`."},"missing_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Present only when the request used `ids=`: the requested ids that were not\nreturned (unknown, another resource type or metro, or no longer active),\nin request order, without repeats.\n"},"min_confidence":{"type":"number","description":"The threshold applied."},"occurrences":{"type":"string","enum":["expand"],"description":"Present when the list is one item per occurrence (`occurrences=expand`)."},"window":{"type":["object","null"],"description":"The resolved date window, so a defaulted `to` is visible and a cursor\ncan be re-issued for exactly this traversal. `null` on `/places`,\nwhich has no window; `to` is `null` on `/classes` and `/camps` when\nnot given (their window is open-ended).\n","required":["from","to","timezone"],"properties":{"from":{"type":"string","format":"date"},"to":{"type":["string","null"],"format":"date"},"timezone":{"type":"string","description":"The metro's IANA zone the dates are read in."}}},"search":{"type":"object","description":"Present when `q=` was given.","required":["query","capped"],"properties":{"query":{"type":"string"},"capped":{"type":"boolean","description":"Very broad queries may be capped; when they are, this is true — add filters or a more specific `q` to narrow results."}}},"geo":{"type":"object","description":"**Present only when beta geo filters are enabled**, and only when this\nrequest was spatial (`lat`/`lng` or `near_zip`, each with\n`radius_m`) or ZIP-filtered (`zip=`).\n","properties":{"origin":{"type":"object","description":"Present when `near_zip=` resolved an origin.","required":["lat","lng","method","vintage"],"properties":{"lat":{"type":"number"},"lng":{"type":"number"},"method":{"type":"string","enum":["zcta_internal_point"]},"vintage":{"type":"string","description":"The current-vintage ZCTA5 boundary set the point was loaded from."}}},"excluded_without_coordinates":{"type":"integer","description":"Present on any spatial query. Rows the radius walk scanned and\ndropped for having no usable point — no coordinates at all, or\na `geo_precision` this query does not surface (`unknown`\nalways, `zip_centroid`/`place` unless `include_approximate=true`).\nNot a count of rows merely outside the circle.\n"}}},"generated_at":{"type":"string","format":"date-time"}}},"Event":{"type":"object","description":"One occurrence.","required":["id","type","name","starts_local","has_time","has_date","timezone","starts_at","is_recurring","place","location","price","ages","categories","occasions","teams","confidence","verified_at","metro","status","updated_at","links"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","const":"event"},"slug":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"starts_local":{"type":["string","null"],"description":"Local wall-clock start, ISO 8601 **without offset**. Midnight when\n`has_time` is false. `null` when `has_date` is false — the listing\nhas no stated start date at all (a dateless recurring series such\nas an all-day carousel ride, not a parse failure).\n","examples":["2026-09-12T10:00:00"]},"ends_local":{"type":["string","null"],"description":"Local wall-clock end, or null when the page states none (never a copy of the start)."},"start_time":{"type":["string","null"],"description":"`HH:MM:SS` local, only when `has_time`.","examples":["10:00:00"]},"has_time":{"type":"boolean","description":"Known precisely when the source stated a time; for older rows, inferred from whether the stored time is midnight."},"has_date":{"type":"boolean","description":"Whether this event has a stated start date at all. `false` means\n`starts_at`/`starts_local` are both `null` — the row is a dateless\nlisting (e.g. a recurring series with no anchor date), not a data\nerror. Mirrors `has_time`. There is no query parameter to select on\nthis yet; the default `from`/`to` window never returns a dateless\nrow, since it has nothing to compare against, so today these are\nreachable only by `id` or `slug`.\n"},"all_day":{"type":"boolean"},"timezone":{"type":"string","description":"IANA zone the conversion used."},"starts_at":{"type":["string","null"],"format":"date-time","description":"UTC instant, or `null` when `has_date` is false. Corrected 2026-09 — this field used to serialise `\"\"` for a dateless event, which is not a valid date-time."},"ends_at":{"type":["string","null"],"format":"date-time"},"occurrence":{"description":"On a list with `occurrences=expand`, the occurrence this item stands\nfor (`ExpandedOccurrence`). Otherwise, where present, the next live\noccurrence (`NextOccurrence`). Either way `starts_at` /\n`starts_local` on the event remain the series' first stated\noccurrence.\n","oneOf":[{"$ref":"#/components/schemas/NextOccurrence"},{"$ref":"#/components/schemas/ExpandedOccurrence"}]},"is_recurring":{"type":"boolean"},"rrule":{"type":["string","null"],"description":"RFC 5545 RRULE, e.g. `FREQ=WEEKLY;BYDAY=SA`."},"recurrence_description":{"type":["string","null"]},"place":{"$ref":"#/components/schemas/PlaceRef"},"location":{"$ref":"#/components/schemas/Location"},"price":{"$ref":"#/components/schemas/Price"},"ages":{"$ref":"#/components/schemas/Ages"},"audience":{"$ref":"#/components/schemas/ListingAudience"},"traits":{"$ref":"#/components/schemas/Traits"},"is_indoor":{"type":["boolean","null"],"description":"Whether the linked place is indoors, as the place states it. Inherited\nthrough `place.id`, never inferred from this listing's title or text.\n`null` means unknown: no linked place, or the place does not say.\n"},"is_outdoor":{"type":["boolean","null"],"description":"Whether the linked place is outdoors, as the place states it; `null` when unknown. A place can be both."},"good_for_rainy":{"type":["boolean","null"],"description":"Whether the linked place states it suits a rainy day; `null` when unknown."},"is_sensory_friendly":{"type":["boolean","null"],"description":"Whether the linked place advertises sensory-friendly accommodation (quiet spaces, low stimulation); `null` when unknown."},"occasions":{"type":"array","items":{"$ref":"#/components/schemas/Occasion"},"description":"Seasonal occasions this listing is tagged for, around each occasion's season. Empty when none."},"teams":{"type":"array","items":{"$ref":"#/components/schemas/Team"},"description":"Local pro sports teams this event is built around. Empty when none."},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"},"description":"All categories for the listing. The first is usually the primary one, but not always; a dedicated primary field is coming."},"registration_url":{"type":["string","null"],"format":"uri","description":"The registration link, when one is stated separately from the source page."},"ticket_url":{"type":["string","null"],"format":"uri"},"registration_required":{"type":"boolean"},"is_sold_out":{"type":"boolean"},"image_url":{"type":["string","null"],"format":"uri"},"organization":{"$ref":"#/components/schemas/OrganizationRef"},"confidence":{"$ref":"#/components/schemas/ConfidenceScore"},"verified_at":{"type":["string","null"],"format":"date-time","description":"When we last confirmed the source page still states this listing. Null for a listing not yet verified, or one that has never been verified."},"metro":{"type":"string","description":"Metro slug."},"status":{"$ref":"#/components/schemas/ListingStatus"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"The latest of the listing's own update and its event details; drives `changed_since`."},"links":{"$ref":"#/components/schemas/ListingLinks"},"expanded":{"$ref":"#/components/schemas/Expanded"},"source":{"$ref":"#/components/schemas/Source"},"forecast":{"$ref":"#/components/schemas/Forecast"},"related":{"$ref":"#/components/schemas/Related"}},"examples":[{"id":"2f3c9d4e-3d2b-4b7d-9a3e-1b2c3d4e5f60","type":"event","slug":"storytime-in-the-park-2026-09-12","name":"Storytime in the Park","description":"Bring a blanket. Ages 2-5.","starts_local":"2026-09-12T10:00:00","ends_local":"2026-09-12T10:45:00","start_time":"10:00:00","has_time":true,"has_date":true,"all_day":false,"timezone":"America/New_York","starts_at":"2026-09-12T14:00:00Z","ends_at":"2026-09-12T14:45:00Z","is_recurring":true,"rrule":"FREQ=WEEKLY;BYDAY=SA","recurrence_description":"Every Saturday through October","place":{"id":"8c1e0a1e-0b2c-4d3e-9f10-1a2b3c4d5e6f","slug":"clark-park","name":"Clark Park"},"location":{"address":"Clark Park, 4300 Baltimore Ave, Philadelphia, PA 19104","street_address":"4300 Baltimore Ave","city":"Philadelphia","state":"PA","zip":"19104","lat":39.9489,"lng":-75.2098,"neighborhood":"University City","neighborhood_slug":"university-city"},"price":{"type":"free","min":null,"max":null,"scope":"admission","note":"Free","unit":null,"is_free":true,"currency":"USD"},"ages":{"min":2,"max":5,"text":null,"audience":"kids","bands":["toddler","preschool"]},"categories":["storytime_books"],"registration_url":null,"ticket_url":null,"registration_required":false,"is_sold_out":false,"image_url":null,"organization":{"id":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d","name":"Friends of Clark Park","slug":"friends-of-clark-park"},"confidence":0.9,"verified_at":null,"metro":"philadelphia","status":"published","created_at":"2026-08-30T02:11:44Z","updated_at":"2026-09-10T06:12:05Z"}]},"Class":{"type":"object","description":"An enrollable program. A program that is offered as several variants (different days, age\ngroups or terms) lists them in `sections`; its own `schedule`, `term`, `ages` and `tuition`\nremain the provider's headline values for the program.\n","required":["id","type","name","program","term","schedule","tuition","price","ages","place","location","categories","occasions","registration","sections_total","sections","sessions","confidence","verified_at","metro","status","updated_at","links"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","const":"class"},"slug":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"program":{"type":"object","properties":{"enrollment_type":{"type":["string","null"],"enum":["enrollment","unknown",null]},"skill_level_notes":{"type":["string","null"]},"adult_participation":{"type":["string","null"],"description":"Whether a parent or caregiver takes part or has to stay. One of `required`, `optional`,\n`drop_off`, `not_allowed` or `varies`. Which of these appear depends on what each provider\nstates, so treat the set as open and handle an unrecognised value as \"not stated\".\n`null` means the source does not state it for this class. It never means \"no adult needed\", and\nit is not inferred from the ages. Providers often put this rule on a separate FAQ or policy\npage rather than on the class itself.\n"},"what_youll_learn":{"type":["string","null"]},"prerequisites":{"type":["string","null"]}}},"term":{"type":"object","description":"The dated block the tuition buys.","properties":{"name":{"type":["string","null"],"description":"e.g. \"Fall 2026\"."},"starts_on":{"type":["string","null"],"format":"date"},"ends_on":{"type":["string","null"],"format":"date"},"total_classes":{"type":["integer","null"],"description":"Number of class meetings in the series, only when the class's own text states it (for\nexample \"8 classes\" or an \"8-week session\" that meets once a week). `null` means the source\ndoes not state it, including for rolling, drop-in, open and year-round classes, which have no\ntotal. It is not worked out from the term dates, and a stated total can differ from the\nmeetings actually held if the provider skips a week.\n"}}},"schedule":{"type":"object","properties":{"type":{"type":["string","null"],"description":"One of `session`, `ongoing`, ..."},"days":{"type":"array","items":{"type":"string"},"description":"Lower-case weekday names."},"start_time":{"type":["string","null"],"description":"`HH:MM:SS` local."},"end_time":{"type":["string","null"]},"duration_minutes":{"type":["integer","null"]},"is_recurring":{"type":["boolean","null"]},"rrule":{"type":["string","null"],"description":"RFC 5545 RRULE, e.g. `FREQ=WEEKLY;BYDAY=SA`."},"notes":{"type":["string","null"],"description":"Verbatim schedule wording."},"timezone":{"type":"string","description":"Metro timezone (class times have no zone column)."}}},"tuition":{"type":"object","properties":{"amount":{"type":["number","null"]},"from":{"type":["number","null"],"description":"The lowest tuition among the program's `sections`; the program's own `amount` when no\nsection states one. Use it for \"from $X\" displays.\n"},"text":{"type":["string","null"],"description":"Verbatim, e.g. \"$460 / 16-week session\"."},"drop_in_price":{"type":["number","null"],"description":"Price to attend a single class without enrolling in the term, when the provider states one\nfor everyone. `null` means the source does not state it; it does not mean drop-ins are\nunavailable. A price that applies only to some people (members, residents, an age group)\nis not filled.\n"},"trial_price":{"type":["number","null"],"description":"Price of a trial class; `0` is a free trial. `null` means the source does not state a trial\nprice; it does not mean no trial is offered. A trial offered only under conditions is not\nfilled.\n"},"trial_notes":{"type":["string","null"],"description":"The provider's own wording about the trial, when `trial_price` is set."},"currency":{"type":"string","const":"USD"}}},"price":{"$ref":"#/components/schemas/Price"},"ages":{"$ref":"#/components/schemas/Ages"},"audience":{"$ref":"#/components/schemas/ListingAudience"},"traits":{"$ref":"#/components/schemas/Traits"},"is_indoor":{"type":["boolean","null"],"description":"Whether the linked place is indoors, as the place states it. Inherited\nthrough `place.id`, never inferred from this listing's title or text.\n`null` means unknown: no linked place, or the place does not say.\n"},"is_outdoor":{"type":["boolean","null"],"description":"Whether the linked place is outdoors, as the place states it; `null` when unknown. A place can be both."},"good_for_rainy":{"type":["boolean","null"],"description":"Whether the linked place states it suits a rainy day; `null` when unknown."},"is_sensory_friendly":{"type":["boolean","null"],"description":"Whether the linked place advertises sensory-friendly accommodation (quiet spaces, low stimulation); `null` when unknown."},"place":{"$ref":"#/components/schemas/PlaceRef"},"location":{"$ref":"#/components/schemas/Location"},"occasions":{"type":"array","items":{"$ref":"#/components/schemas/Occasion"},"description":"Seasonal occasions this listing is tagged for, around each occasion's season. Empty when none."},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"},"description":"All categories for the listing. The first is usually the primary one, but not always; a dedicated primary field is coming."},"registration":{"type":"object","properties":{"url":{"type":["string","null"],"format":"uri","description":"The registration link, when one is stated separately from the source page."},"status":{"$ref":"#/components/schemas/RegistrationStatus"},"opens_at":{"type":["string","null"],"format":"date-time"},"spots_remaining":{"type":["integer","null"],"description":"Seats left, when the provider publishes a count. Most do not, so this is usually `null`\n(not stated by the source). Use `status` for the registration state.\n"},"has_spots_available":{"type":"boolean","description":"`true` is the default and is not a confirmation that seats are open: it means we have not\nseen the provider say the class is full. `false` is reported only where we have read such a\nstatement, so do not rely on it to find every full class.\n"},"waitlist_available":{"type":"boolean"},"sections_with_spots":{"type":"integer","description":"How many of the program's `sections` are known to have room (seats left, or marked available, and not closed). Sections with unknown availability are not counted."}}},"sections_total":{"type":"integer","description":"How many sections the program has. `0` when it has none."},"sections":{"type":"array","description":"The program's sections (its variants: a day and time, an age group, a term), always present\nand empty when the program has none. `registration.has_spots_available` is `true` when the\nprogram or any section has seats. Filters never trim this list; see `schedule_day`, `age`,\n`openings` and the other filters on the list operation for how a program is matched.\n","items":{"$ref":"#/components/schemas/ClassSection"}},"sessions":{"type":"array","description":"On a list, other classes the program card stands for when a provider's pages publish the same\nprogram as separate listings. Each is a complete class (the same object, without `sessions`)\nthat can also be fetched on its own. Always present; empty on a detail read, on an ungrouped\ncard, and when the request asks for every class on its own with `expand=sessions`.\n","items":{"type":"object"}},"image_url":{"type":["string","null"],"format":"uri"},"organization":{"$ref":"#/components/schemas/OrganizationRef"},"confidence":{"$ref":"#/components/schemas/ConfidenceScore"},"verified_at":{"type":["string","null"],"format":"date-time","description":"When we last confirmed the source page still states this listing. Null for a listing not yet verified, or one that has never been verified."},"metro":{"type":"string"},"status":{"$ref":"#/components/schemas/ListingStatus"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"The latest of the listing's own update and its class details."},"links":{"$ref":"#/components/schemas/ListingLinks"},"expanded":{"$ref":"#/components/schemas/Expanded"},"source":{"$ref":"#/components/schemas/Source"},"related":{"$ref":"#/components/schemas/Related"}}},"ClassSection":{"type":"object","description":"One variant of a class program, such as a day and time, an age group or a term, with its own tuition and availability.","required":["id","name","schedule","term","ages","tuition","registration","updated_at"],"properties":{"id":{"type":"string","description":"Stable identifier of the section within its program."},"name":{"type":["string","null"]},"schedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"string"},"description":"Lower-case weekday names."},"start_time":{"type":["string","null"],"description":"`HH:MM:SS` local."},"end_time":{"type":["string","null"]},"duration_minutes":{"type":["integer","null"]},"rrule":{"type":["string","null"]},"notes":{"type":["string","null"]},"timezone":{"type":"string","description":"Metro timezone."}}},"term":{"type":"object","properties":{"name":{"type":["string","null"]},"starts_on":{"type":["string","null"],"format":"date"},"ends_on":{"type":["string","null"],"format":"date"},"total_classes":{"type":["integer","null"]}}},"ages":{"type":"object","properties":{"min":{"type":["integer","null"]},"max":{"type":["integer","null"]},"text":{"type":["string","null"]}}},"tuition":{"type":"object","properties":{"amount":{"type":["number","null"]},"text":{"type":["string","null"]},"drop_in_price":{"type":["number","null"]},"currency":{"type":"string","const":"USD"}}},"registration":{"type":"object","properties":{"url":{"type":["string","null"],"format":"uri"},"status":{"$ref":"#/components/schemas/RegistrationStatus"},"spots_remaining":{"type":["integer","null"],"description":"Seats left, only when the provider publishes a count."},"has_spots_available":{"type":["boolean","null"],"description":"`null` when the provider does not say."},"waitlist_available":{"type":["boolean","null"]}}},"updated_at":{"type":["string","null"],"format":"date-time"}}},"CampSession":{"type":"object","description":"One dated, priced block of a camp.","required":["id","name","starts_on","ends_on","status"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"starts_on":{"type":"string","format":"date"},"ends_on":{"type":"string","format":"date"},"price":{"type":["number","null"]},"early_bird_price":{"type":["number","null"]},"full_day_price":{"type":["number","null"]},"half_day_price":{"type":["number","null"]},"currency":{"type":"string","const":"USD"},"capacity":{"type":["integer","null"]},"spots_remaining":{"type":["integer","null"]},"status":{"description":"Source-supported enrollment status; null when unknown.","anyOf":[{"$ref":"#/components/schemas/RegistrationStatus"},{"type":"null"}]},"theme":{"type":["string","null"]},"notes":{"type":["string","null"]}}},"Camp":{"type":"object","description":"A camp, with its sessions.","required":["id","type","name","schedule","price","ages","place","location","categories","registration","sessions","confidence","verified_at","metro","status","updated_at","links"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","const":"camp"},"slug":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"season":{"type":["string","null"]},"year":{"type":["integer","null"]},"starts_on":{"type":["string","null"],"format":"date","description":"First day across sessions, when stated."},"ends_on":{"type":["string","null"],"format":"date"},"schedule":{"type":"object","properties":{"type":{"type":["string","null"]},"is_full_day":{"type":"boolean"},"is_half_day_am":{"type":"boolean"},"is_half_day_pm":{"type":"boolean"},"day_start_time":{"type":["string","null"],"description":"`HH:MM:SS` local."},"day_end_time":{"type":["string","null"]},"extended_care":{"type":"object","properties":{"morning_start":{"type":["string","null"]},"morning_price":{"type":["number","null"]},"afternoon_end":{"type":["string","null"]},"afternoon_price":{"type":["number","null"]},"notes":{"type":["string","null"]},"currency":{"type":"string","const":"USD"}}},"timezone":{"type":"string","description":"Metro timezone."}}},"is_overnight":{"type":"boolean"},"is_travel":{"type":"boolean"},"is_specialty":{"type":"boolean"},"pricing_unit":{"type":["string","null"],"description":"One of `per_week`, `per_session`."},"price":{"$ref":"#/components/schemas/Price"},"ages":{"$ref":"#/components/schemas/Ages"},"audience":{"$ref":"#/components/schemas/ListingAudience"},"traits":{"$ref":"#/components/schemas/Traits"},"place":{"$ref":"#/components/schemas/PlaceRef"},"location":{"$ref":"#/components/schemas/Location"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"},"description":"All categories for the listing. The first is usually the primary one, but not always; a dedicated primary field is coming."},"registration":{"type":"object","properties":{"url":{"type":["string","null"],"format":"uri","description":"The registration link, when one is stated separately from the source page."},"opens_on":{"type":["string","null"],"format":"date"},"deadline_on":{"type":["string","null"],"format":"date"},"early_bird_deadline_on":{"type":["string","null"],"format":"date"},"has_spots_available":{"type":["boolean","null"],"description":"True if a session is known open; false if all sessions are known unavailable; null when unknown."},"sessions_with_spots":{"type":"integer"}}},"sessions":{"type":"array","items":{"$ref":"#/components/schemas/CampSession"}},"image_url":{"type":["string","null"],"format":"uri"},"organization":{"$ref":"#/components/schemas/OrganizationRef"},"confidence":{"$ref":"#/components/schemas/ConfidenceScore"},"verified_at":{"type":["string","null"],"format":"date-time","description":"When we last confirmed the source page still states this listing. Null for a listing not yet verified, or one that has never been verified."},"metro":{"type":"string"},"status":{"$ref":"#/components/schemas/ListingStatus"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"The latest of the listing's own update, its camp details, and any of its sessions."},"links":{"$ref":"#/components/schemas/ListingLinks"},"expanded":{"$ref":"#/components/schemas/Expanded"},"source":{"$ref":"#/components/schemas/Source"},"related":{"$ref":"#/components/schemas/Related"}}},"Place":{"type":"object","description":"A place, classified by `type_hint`. A more granular classification\nfield is planned for a future version.\n","required":["id","type","name","type_hint","location","ages","categories","confidence","verified_at","metro","status","updated_at","links"],"properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","const":"place"},"slug":{"type":["string","null"]},"name":{"type":"string"},"description":{"type":["string","null"]},"type_hint":{"$ref":"#/components/schemas/PlaceTypeHint"},"type_hint_notes":{"type":["string","null"]},"location":{"$ref":"#/components/schemas/Location"},"hours":{"type":"object","description":"Verbatim per-day hours; null when unknown.","properties":{"monday":{"type":["string","null"]},"tuesday":{"type":["string","null"]},"wednesday":{"type":["string","null"]},"thursday":{"type":["string","null"]},"friday":{"type":["string","null"]},"saturday":{"type":["string","null"]},"sunday":{"type":["string","null"]},"notes":{"type":["string","null"]},"exceptions":{"type":["string","null"]}}},"admission":{"type":"object","properties":{"type":{"type":["string","null"]},"child_price":{"type":["number","null"]},"adult_price":{"type":["number","null"]},"infant_age_cutoff":{"type":["integer","null"]},"notes":{"type":["string","null"]},"currency":{"type":"string","const":"USD"}}},"membership":{"type":"object","properties":{"available":{"type":"boolean"},"price_monthly":{"type":["number","null"]},"price_annual":{"type":["number","null"]},"notes":{"type":["string","null"]},"currency":{"type":"string","const":"USD"}}},"birthday_parties":{"type":"object","properties":{"available":{"type":"boolean"},"min_guests":{"type":["integer","null"]},"max_guests":{"type":["integer","null"]},"age_range":{"type":["string","null"]},"booking_url":{"type":["string","null"],"format":"uri"},"notes":{"type":["string","null"]}}},"classes":{"type":"object","properties":{"available":{"type":"boolean"},"types":{"type":["array","null"],"items":{"type":"string"}},"age_range":{"type":["string","null"]},"schedule_notes":{"type":["string","null"]},"registration_url":{"type":["string","null"],"format":"uri"}}},"amenities":{"type":"object","properties":{"has_outdoor_space":{"type":["boolean","null"]},"has_parking":{"type":["boolean","null"]},"parking_notes":{"type":["string","null"]},"has_wifi":{"type":["boolean","null"]},"socks_required":{"type":["boolean","null"]},"outside_food_allowed":{"type":["boolean","null"]},"stroller_policy":{"type":["string","null"]}}},"is_sensory_friendly":{"type":["boolean","null"],"description":"Whether the place advertises sensory-friendly accommodation (quiet spaces, low stimulation). `null` when the place does not say; places usually state it only when true. Events and classes at this place inherit it."},"ages":{"$ref":"#/components/schemas/Ages"},"audience":{"$ref":"#/components/schemas/ListingAudience"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"},"description":"All categories for the listing. The first is usually the primary one, but not always; a dedicated primary field is coming."},"image_url":{"type":["string","null"],"format":"uri"},"images":{"type":["array","null"],"items":{"type":"string","format":"uri"},"description":"More photos of the place, after `image_url` (the primary image), deduplicated. Hosted by the provider's own site; link or attribute to `website_url` when displaying. `null` on `include_archived` detail reads, where it is not available."},"website_url":{"type":["string","null"],"format":"uri","description":"Same as `source.url` (`include=source`) for places parsed from their own site."},"organization":{"$ref":"#/components/schemas/OrganizationRef"},"confidence":{"$ref":"#/components/schemas/ConfidenceScore"},"verified_at":{"type":["string","null"],"format":"date-time","description":"When we last confirmed the source page still states this listing. Null for a listing not yet verified, or one that has never been verified."},"metro":{"type":"string"},"status":{"$ref":"#/components/schemas/ListingStatus"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","description":"The latest of the listing's own update and its place details."},"links":{"$ref":"#/components/schemas/PlaceLinks"},"expanded":{"$ref":"#/components/schemas/Expanded"},"source":{"$ref":"#/components/schemas/Source"}}},"Change":{"type":"object","additionalProperties":false,"description":"One privacy-safe, value-free version row from the changes feed.","required":["version_id","listing_id","type","changed_at","kind","fields"],"properties":{"version_id":{"type":"integer","format":"int64","description":"Monotonic — use as the cursor."},"listing_id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"],"description":"The listing's slug, so a removal can be turned into the path to\nrevalidate. Read from the listing when it still exists; for a row\nthat is gone, from what the version row captured — a hard delete\nrecords every contract field the row had. `null` only when\nneither has one.\n"},"type":{"$ref":"#/components/schemas/ListingType"},"metro":{"type":["string","null"],"description":"Metro slug (captured on the version row, so deletes keep it)."},"changed_at":{"type":"string","format":"date-time"},"kind":{"$ref":"#/components/schemas/ListingVersion/properties/kind"},"fields":{"$ref":"#/components/schemas/ListingVersion/properties/fields"}},"examples":[{"version_id":18231,"listing_id":"2f3c9d4e-3d2b-4b7d-9a3e-1b2c3d4e5f60","slug":"storytime-in-the-park-2026-09-12","type":"event","metro":"philadelphia","changed_at":"2026-09-10T06:12:05Z","kind":"date_changed","fields":["starts_at"]}]},"SearchResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"meta":{"$ref":"#/components/schemas/SearchMeta"}}},"SearchResult":{"type":"object","description":"A collection-shaped listing plus cross-type search fields.","required":["type","id","slug","name","snippet","match","score"],"properties":{"type":{"type":"string","enum":["event","class","camp","place"]},"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"snippet":{"type":"string","maxLength":180},"score":{"type":"number","minimum":0,"maximum":1,"description":"How well this listing fits the query's words, from 0 to 1. Absolute:\nnot scaled against the other results, so it is comparable between\nresults and between queries. Not a probability.\n"},"match":{"type":"string","enum":["all_terms","related","partial"],"description":"How directly the listing matches. `all_terms`: every word you\ntyped is in its name or category, or prominent in the opening of its\ndescription. `related`: every word is covered that way, but at\nleast one only through a closely related word (for example\n`ceramics` for `pottery`). `partial`: only some of the words, or all\nof them only mentioned in passing further down a description.\nReturned only when `match` asks for it. A result found by meaning\nalone is `related`.\n"}}},"SearchMeta":{"type":"object","required":["query","types","ranking","ignored_words","interpreted","match","match_counts","sort","count_estimate","capped","limit","count","has_more","next_cursor","generated_at","applied_filters","defaults_applied"],"properties":{"applied_filters":{"type":"object","description":"The filters every searched type was computed with (`audience`, and whichever of\n`category`, `q`, `lat`/`lng`/`radius_m` and the rest you sent). The ones that\ndiffer by type, `from`, `to` and `min_confidence`, are under `by_type`, keyed by\ncollection (`events`, `classes`, `camps`, `places`). See `AppliedFilters`.\n","additionalProperties":true,"properties":{"by_type":{"type":"object","additionalProperties":{"type":"object","properties":{"from":{"type":"string","format":"date"},"to":{"type":["string","null"],"format":"date"},"min_confidence":{"type":"number"}}}}}},"defaults_applied":{"$ref":"#/components/schemas/DefaultsApplied"},"query":{"type":"string"},"types":{"type":"array","items":{"type":"string","enum":["events","classes","camps","places"]}},"ranking":{"type":"string","enum":["keyword","hybrid"]},"ignored_words":{"type":"array","items":{"type":"string"},"description":"Words from the query that were left out of matching: audience words\n(such as `parents` or `kids`) and time or price words (such as\n`tonight` or `cheap`) when other words were present. Empty when\nnothing was left out.\n"},"interpreted":{"type":"object","description":"What the search read out of the query and applied for you. Empty when nothing was.","properties":{"age":{"type":"object","description":"The age band read from the query (`5 year olds`, `ages 3-5`, `toddlers`) and applied as an age filter. When you sent `age` or `audience` yourself the band is still reported but not applied, and `overridden_by` names the parameter.","required":["min","max","from"],"properties":{"overridden_by":{"type":"string","enum":["age","audience"]},"min":{"type":"integer"},"max":{"type":"integer"},"from":{"type":"string","description":"The words in the query the band was read from."}}}}},"match":{"type":"array","items":{"type":"string","enum":["all_terms","related","partial"]},"description":"The match levels returned, from the `match` parameter or its default."},"match_counts":{"type":"object","required":["all_terms","related","partial"],"description":"How many results there are at each match level among what this search can see, whatever `match` selected. `count_estimate` counts only the selected levels.","properties":{"all_terms":{"type":"integer"},"related":{"type":"integer"},"partial":{"type":"integer"}}},"sort":{"type":"string","enum":["relevance","soonest","nearest","newest"]},"count_estimate":{"type":"integer","description":"Visible result count for this search; it may be capped for very broad queries."},"capped":{"type":"boolean","description":"True when this broad query was capped; add filters or a more specific q to narrow the results."},"limit":{"type":"integer"},"count":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Opaque continuation cursor. A search cursor whose ranking mode is\nno longer available returns `400 bad_request` with\n`details.reason: cursor_expired`; restart without it.\n"},"generated_at":{"type":"string","format":"date-time"}}},"NextOccurrence":{"type":"object","description":"The next live occurrence of an event.","required":["next_starts_at","next_starts_local"],"properties":{"next_starts_at":{"type":["string","null"],"format":"date-time","description":"UTC instant of the next occurrence, or null when the series has ended or no occurrence is known."},"next_starts_local":{"type":["string","null"],"description":"Local wall-clock time of `next_starts_at`, or null when there is none."}}},"ExpandedOccurrence":{"type":"object","description":"One occurrence of an event, as listed by `occurrences=expand`.","required":["starts_local","ends_local","starts_at","ends_at","index"],"properties":{"starts_local":{"type":"string","description":"Local wall-clock start in the metro's timezone, `YYYY-MM-DDTHH:MM:SS`.","examples":["2026-10-06T10:00:00"]},"ends_local":{"type":["string","null"],"description":"Local wall-clock end, or null when the event states none."},"starts_at":{"type":"string","format":"date-time","description":"UTC instant of `starts_local`."},"ends_at":{"type":["string","null"],"format":"date-time"},"index":{"type":"integer","minimum":0,"description":"The occurrence's position in its series: `0` for the first stated\noccurrence, then `1`, `2`, … . Stable for a given series, so `id`\nplus `index` identifies one occurrence. Always `0` for a one-off.\n"}}},"CalendarDay":{"type":"object","required":["date","count","free_count","categories"],"properties":{"date":{"type":"string","format":"date","description":"A local date in the metro's timezone."},"count":{"type":"integer","description":"Occurrences starting on this date — exactly the items `/events?occurrences=expand` lists for it under the same filters."},"free_count":{"type":"integer","description":"How many of `count` are free."},"categories":{"type":"object","description":"Occurrences per category slug on this date. An occurrence with several categories counts toward each; categories with no occurrences are left out.","additionalProperties":{"type":"integer"}},"forecast":{"$ref":"#/components/schemas/CalendarDayForecast"}}},"CalendarDayForecast":{"type":"object","description":"Present with `include=forecast` (a paid add-on) on today and each of\nthe next seven days, when forecast data covers the whole day. The\nforecast is for the metro's centre.\n","required":["summary","temperature_f","precipitation_chance_max","wet_hours","issued_at","expires_at"],"properties":{"issued_at":{"type":"string","format":"date-time","description":"When this forecast was issued (UTC)."},"expires_at":{"type":"string","format":"date-time","description":"When this forecast stops being fresh (UTC). The response's\n`Cache-Control` max-age never runs past it; refetch after it.\n"},"summary":{"type":"string","description":"A short description of the day's weather."},"temperature_f":{"type":"object","required":["min","max"],"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"precipitation_chance_max":{"type":["number","null"],"description":"The day's highest hourly chance of precipitation, in percent."},"wet_hours":{"type":"array","description":"Local `[startHour, endHour)` ranges, 0–24, of hours with a high\nchance of precipitation; adjacent hours are merged. Empty on a dry day.\n","items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"integer"}},"examples":[[[9,13],[15,17]]]}}},"EventCalendar":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","description":"One entry per date in `[from, to]`, in order, including dates with no occurrences.","items":{"$ref":"#/components/schemas/CalendarDay"}},"meta":{"type":"object","required":["metro","window","min_confidence","total","applied_filters","defaults_applied"],"properties":{"metro":{"type":"string"},"window":{"type":"object","required":["from","to","timezone"],"properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"timezone":{"type":"string"}}},"min_confidence":{"type":"number"},"total":{"type":"integer","description":"The sum of `count` over the window."},"applied_filters":{"$ref":"#/components/schemas/AppliedFilters"},"defaults_applied":{"$ref":"#/components/schemas/DefaultsApplied"},"generated_at":{"type":"string","format":"date-time"}}},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"EventList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"meta":{"$ref":"#/components/schemas/ListMeta"},"facets":{"$ref":"#/components/schemas/Facets"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"ClassList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Class"}},"meta":{"$ref":"#/components/schemas/ListMeta"},"facets":{"$ref":"#/components/schemas/Facets"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"CampList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Camp"}},"meta":{"$ref":"#/components/schemas/ListMeta"},"facets":{"$ref":"#/components/schemas/Facets"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"PlaceList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Place"}},"meta":{"$ref":"#/components/schemas/ListMeta"},"facets":{"$ref":"#/components/schemas/Facets"},"notices":{"type":"array","items":{"$ref":"#/components/schemas/Notice"},"description":"Present only when there is at least one — see `Notice`."}}},"ChangeList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Change"}},"meta":{"type":"object","required":["limit","count","has_more"],"properties":{"since":{"type":"string","format":"date-time"},"metro":{"type":["string","null"]},"limit":{"type":"integer"},"count":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"The position to pass as `cursor` on the next request. It can advance even when `data` is empty."},"generated_at":{"type":"string","format":"date-time"}}}}},"Expanded":{"type":"object","description":"Present only when `expand=` was given; each key present only when asked for.","properties":{"place":{"oneOf":[{"$ref":"#/components/schemas/Place"},{"type":"null"}],"description":"The full place behind `place.id`, or null when the row has none (or it is no longer published)."},"organization":{"oneOf":[{"$ref":"#/components/schemas/OrganizationCore"},{"type":"null"}]}}},"OrganizationCore":{"type":"object","description":"An `Organization` without `metros`.","required":["id","name","links"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":["string","null"]},"organization_type":{"type":["string","null"]},"website_url":{"type":["string","null"],"format":"uri","description":"The organization's own website. On `GET /v1/{metro}/organizations`, when none is recorded, the address of the site the organization itself runs, if we have one."},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"is_verified":{"type":["boolean","null"]},"links":{"$ref":"#/components/schemas/OrganizationLinks"}}},"LiveCounts":{"type":"object","description":"Published, active listings, by type. `listings` is the total including `ongoing`.","required":["listings","events","classes","camps","places"],"properties":{"listings":{"type":"integer"},"events":{"type":"integer"},"classes":{"type":"integer"},"camps":{"type":"integer"},"places":{"type":"integer"}}},"OrganizationEntry":{"type":"object","description":"One organization with live counts in a metro.","required":["id","name","metro","live"],"allOf":[{"$ref":"#/components/schemas/OrganizationCore"}],"properties":{"metro":{"type":"string"},"live":{"$ref":"#/components/schemas/LiveCounts"},"updated_at":{"type":["string","null"],"format":"date-time","description":"The most recent `updated_at` among its live listings here."},"score":{"type":"number","minimum":0,"maximum":1,"description":"Present only when `q` was sent. How closely the organization matches what was typed, 0 to 1; higher is closer. It does not depend on the other results."},"match":{"type":"string","enum":["exact_name","exact_domain","name","domain","fuzzy"],"description":"Present only when `q` was sent. `exact_name`, `exact_domain`, the whole name or address was typed; `name`, `domain`, the same words once spelling, spacing and endings are set aside, or the start or a word of it; `fuzzy`, a small typo away."}},"examples":[{"id":"5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d","name":"Friends of Clark Park","slug":"friends-of-clark-park","organization_type":"nonprofit","website_url":"https://www.friendsofclarkpark.org","city":"Philadelphia","state":"PA","is_verified":true,"metro":"philadelphia","live":{"listings":12,"events":10,"classes":0,"camps":1,"places":1},"updated_at":"2026-09-10T06:12:05Z"}]},"OrganizationList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationEntry"}},"meta":{"$ref":"#/components/schemas/DirectoryMeta"}}},"Neighborhood":{"type":"object","description":"One neighborhood with live counts in a metro.","required":["id","name","metro","live","aliases"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":["string","null"],"description":"What `neighborhood=` on the collections takes."},"aliases":{"type":"array","items":{"type":"string"}},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"metro":{"type":"string"},"live":{"$ref":"#/components/schemas/LiveCounts"}},"examples":[{"id":"9a9a9a9a-0000-4000-8000-000000000001","name":"University City","slug":"university-city","aliases":["UCity"],"lat":39.95,"lng":-75.2,"metro":"philadelphia","live":{"listings":40,"events":30,"classes":5,"camps":2,"places":3}}]},"NeighborhoodList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Neighborhood"}},"meta":{"$ref":"#/components/schemas/DirectoryMeta"}}},"DirectoryMeta":{"type":"object","required":["metro","limit","count","has_more"],"properties":{"metro":{"type":"string"},"page":{"type":["integer","null"]},"limit":{"type":"integer"},"count":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Opaque, bound to the request, as on the collections."},"hint":{"type":"string","description":"Present only when `q` had nothing to search by (empty, or only words like `the` and `and` and endings like `llc`). Says what to search by instead."},"generated_at":{"type":"string","format":"date-time"}}},"Coverage":{"type":"object","description":"Coverage statistics for a metro, computed at read time.","required":["metro","timezone","counts","events","freshness","fields","organizations","sources","generated_at"],"properties":{"metro":{"type":"string"},"timezone":{"type":"string"},"counts":{"type":"object","description":"Published, active listings by type under the public names (`event`, `class`, `camp`, `place`, `ongoing`).","additionalProperties":{"type":"integer"}},"events":{"type":"object","properties":{"future":{"type":"integer","description":"Events starting from now on."},"next_7_days":{"type":"integer"},"next_30_days":{"type":"integer"},"future_recurring":{"type":"integer"},"horizon":{"type":["string","null"],"format":"date-time","description":"The latest start on file."}}},"freshness":{"type":"object","description":"How current the metro's live listings are, as outcomes a buyer can act on rather than pipeline measurements.","required":["confirmed_last_7d_pct","confirmed_last_30d_pct","upcoming_48h_confirmed_12h_pct","median_source_age_days"],"properties":{"confirmed_last_7d_pct":{"type":["number","null"],"description":"Percent (0-100, one decimal) of currently served listings last confirmed within 7 days. `null` when the metro serves nothing."},"confirmed_last_30d_pct":{"type":["number","null"],"description":"Same, over 30 days."},"upcoming_48h_confirmed_12h_pct":{"type":["number","null"],"description":"Of events starting in the next 48 hours, percent confirmed within the last 12 hours. `null` when none start in that window."},"median_source_age_days":{"type":["number","null"],"description":"Median age, in days, of the source page each live row was last read from."}}},"fields":{"type":"object","description":"Over live non-place rows.","properties":{"total":{"type":"integer"},"with_organization":{"type":"integer"},"with_neighborhood":{"type":"integer"},"with_place":{"type":"integer","description":"Rows linked to a place listing (`place.id` non-null)."},"with_coordinates":{"type":"integer"}}},"organizations":{"type":"integer","description":"Distinct organizations with live listings."},"sources":{"type":"object","properties":{"total":{"type":"integer","description":"Distinct source sites belonging to organizations with live listings in the metro."}}},"generated_at":{"type":"string","format":"date-time"}},"examples":[{"metro":"philadelphia","timezone":"America/New_York","counts":{"event":1583,"class":648,"camp":88,"place":983,"ongoing":16},"events":{"future":950,"next_7_days":165,"next_30_days":500,"future_recurring":460,"horizon":"2027-06-01T00:00:00Z"},"freshness":{"confirmed_last_7d_pct":62.3,"confirmed_last_30d_pct":84.1,"upcoming_48h_confirmed_12h_pct":58,"median_source_age_days":8.8},"fields":{"total":2335,"with_organization":2167,"with_neighborhood":1380,"with_place":1823,"with_coordinates":1340},"organizations":357,"sources":{"total":357},"generated_at":"2026-09-13T12:00:00Z"}]},"VersionList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ListingVersion"}},"meta":{"type":"object","required":["listing_id","limit","count","has_more"],"properties":{"listing_id":{"type":"string","format":"uuid"},"limit":{"type":"integer"},"count":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"The last `version_id` in this page, as a string; pass as `cursor` for older versions."},"generated_at":{"type":"string","format":"date-time"}}}}},"ListingVersion":{"type":"object","additionalProperties":false,"description":"A public, value-free summary of one listing change.","required":["changed_at","kind","fields"],"properties":{"changed_at":{"type":"string","format":"date-time","description":"When the change occurred, in UTC."},"kind":{"type":"string","enum":["created","updated","date_changed","price_changed","location_changed","archived","restored"]},"fields":{"type":"array","uniqueItems":true,"description":"Sorted names of changed public fields. Internal and unknown fields are omitted.","items":{"type":"string","enum":["admission","ages","all_day","birthday_parties","categories","description","ends_at","ends_local","ends_on","has_time","hours","image_url","images","is_overnight","is_recurring","is_sold_out","is_specialty","is_travel","location","membership","name","organization","place","price","pricing_unit","program","recurrence_description","registration","registration_required","registration_url","rrule","schedule","season","sections","sessions","slug","start_time","starts_at","starts_local","starts_on","status","term","ticket_url","timezone","tuition","type_hint","type_hint_notes","year"]}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["bad_request","unauthorized","forbidden","include_not_permitted","feature_not_in_plan","not_found","method_not_allowed","rate_limited","quota_exceeded","internal","not_implemented","unavailable"],"description":"A closed set. Branch on this, never on the message.\n\nEvery code but the two 429s and the three 403s rides on exactly\none status:\n\n| status | code | what to do |\n| --- | --- | --- |\n| 400 | `bad_request` | fix the request |\n| 401 | `unauthorized` | get a working key |\n| 403 | `forbidden` | read `details` and degrade |\n| 403 | `include_not_permitted` | drop the `include=`, upgrade, or retry with `include_mode=lenient` |\n| 403 | `feature_not_in_plan` | upgrade or use a key with the named feature grant |\n| 404 | `not_found` | change the input |\n| 405 | `method_not_allowed` | use `GET`; read `Allow` |\n| 429 | `rate_limited` | sleep `Retry-After`, retry |\n| 429 | `quota_exceeded` | **do not** retry; buy capacity |\n| 500 | `internal` | retry once, then report the `request_id` |\n| 501 | `not_implemented` | disable the feature; do not retry |\n| 503 | `unavailable` | retry after `Retry-After` |\n\n`rate_limited` and `quota_exceeded` are one deliberate\ncollision — both `429`, the first the per-minute rate, the\nsecond the monthly allowance or a hard cap. The three `403`\ncodes distinguish a scope refusal, an\nentitlement refusal on an `include=` add-on, and a premium\nendpoint outside the effective plan. Branch on the code, not\nthe status.\n"},"message":{"type":"string"},"details":{"type":["object","null"],"additionalProperties":true,"description":"Machine-readable context (which parameter failed, which scopes the key has)."},"request_id":{"type":"string"}}}}},"Related":{"type":"object","description":"Present with `include=related` on a single event, class or camp (see\n`Include`). Three lists of at most six cards each, from the same\nlistings the list endpoints serve to the same key.\n","required":["similar","from_organization","at_place"],"properties":{"similar":{"type":"array","maxItems":6,"description":"Nearby listings of the same kind, in the same Monday-to-Sunday week\nas this listing's date (the next date, for a series), in a matching\ncategory, with overlapping ages (unstated ages overlap). Never this\nlisting, its series, its organization or its place. Nearest first,\nthen closest in date.\n","items":{"$ref":"#/components/schemas/RelatedCard"}},"from_organization":{"type":"array","maxItems":6,"description":"The organization's next upcoming listings of the same type, soonest first, one card per series, without this listing.","items":{"$ref":"#/components/schemas/RelatedCard"}},"at_place":{"type":"array","maxItems":6,"description":"Other listings at the same place in the same week, soonest first, without this listing.","items":{"$ref":"#/components/schemas/RelatedCard"}}}},"RelatedCard":{"type":"object","description":"A listing, briefly. Fetch the listing by `id` for the rest.","required":["id","type","name","is_free"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"]},"type":{"type":"string","enum":["event","class","camp"]},"name":{"type":"string"},"starts_at":{"type":["string","null"],"format":"date-time","description":"Events: the start (UTC) of the relevant occurrence, the next one for a series. Null for classes and camps."},"ends_at":{"type":["string","null"],"format":"date-time"},"starts_on":{"type":["string","null"],"format":"date","description":"Events: the local date of the occurrence. Classes and camps: the term or span start."},"ends_on":{"type":["string","null"],"format":"date"},"place":{"type":["object","null"],"properties":{"id":{"type":["string","null"],"format":"uuid"},"name":{"type":["string","null"]}}},"image_url":{"type":["string","null"],"format":"uri"},"price":{"description":"The listing's price, as the list endpoints return it.","oneOf":[{"$ref":"#/components/schemas/Price"},{"type":"null"}]},"is_free":{"type":"boolean"}}},"Notice":{"type":"object","description":"A non-fatal condition on an otherwise-successful (`200`) response —\nsuch as `include_mode=lenient` omitting an unentitled `include=`, or\nrequested forecast data being temporarily unavailable.\n`notices` (plural, top level, a sibling of `data`/`meta`) carries zero\nor more of these; absent, not an empty array, when there is nothing\nto say.\n","required":["code","message"],"properties":{"code":{"type":"string","enum":["include_not_permitted","forecast_unavailable","related_unavailable"],"description":"The same vocabulary as `Error.code`, for the same reason — branch on this, not on `message`."},"include":{"type":"string","description":"Which `include=` value this notice concerns."},"message":{"type":"string"},"upgrade_url":{"type":"string","format":"uri","description":"Where to compare plans when the omitted include is available by upgrade."}}},"Forecast":{"type":"object","description":"Event-window conditions in degrees Fahrenheit and miles per hour.\nHourly detail is used when the event starts within 48 hours; later\nevents summarize the event's calendar day in its metro timezone. The\nwindow is start to end, or start to two hours later when no end is\nstated. The key is omitted for ineligible events or when data is\ntemporarily unavailable.\n","required":["granularity","issued_at","window_start_at","window_end_at","summary","temperature_f","precipitation_chance_max","wind_mph_max"],"properties":{"granularity":{"type":"string","enum":["hourly","daily"]},"issued_at":{"type":"string","format":"date-time"},"window_start_at":{"type":"string","format":"date-time"},"window_end_at":{"type":"string","format":"date-time"},"summary":{"type":"string"},"temperature_f":{"type":"object","required":["min","max"],"properties":{"min":{"type":"number"},"max":{"type":"number"}}},"precipitation_chance_max":{"type":["number","null"],"minimum":0,"maximum":100},"wind_mph_max":{"type":["number","null"],"minimum":0},"periods":{"type":"array","description":"Present only for hourly forecasts; contains the event's hours.","items":{"type":"object","required":["starts_at","temperature_f","precipitation_chance","wind_mph","summary"],"properties":{"starts_at":{"type":"string","format":"date-time"},"temperature_f":{"type":"number"},"precipitation_chance":{"type":["number","null"],"minimum":0,"maximum":100},"wind_mph":{"type":["number","null"],"minimum":0},"summary":{"type":"string"}}}}}},"ActivityComponents":{"type":"object","description":"The counts and distances behind `activity_score`, computed over the rows described on the operation.","required":["events_30d","events_per_week","recurring_programs","classes","camps","places_total","places_by_type"],"properties":{"events_30d":{"type":"integer","description":"Events starting inside the window (`days`, default 30)."},"events_per_week":{"type":"number","description":"`events_30d` normalised to a week, so a 7-day and a 90-day window are comparable."},"recurring_programs":{"type":"integer","description":"Distinct events in the window flagged `is_recurring` — a weekly storytime, not a one-off."},"classes":{"type":"integer","description":"Live classes whose term has not ended (or that are `ongoing`)."},"camps":{"type":"integer","description":"Live camps whose span has not ended. Past summer camps are not counted."},"places_total":{"type":"integer"},"places_by_type":{"type":"object","additionalProperties":{"type":"integer"},"description":"Place counts keyed by `PlaceTypeHint`."},"nearest_library_m":{"type":["integer","null"],"description":"Metres to the nearest library. Null when there is none in the radius."},"nearest_park_m":{"type":["integer","null"]},"nearest_playground_m":{"type":["integer","null"],"description":"Nearest `play_space`, or a place whose name or tags say playground. `playground` is not a `PlaceTypeHint`."},"nearest_museum_m":{"type":["integer","null"]},"free_share":{"type":["number","null"],"description":"Share of the window's events that are free, 0-1. Null when there are no events to take a share of."},"age_band_coverage":{"type":"object","description":"Which of the four age bands (`baby`, `toddler`, `young_kids`, `bigger_kids`) anything nearby serves.","properties":{"bands":{"type":"object","additionalProperties":{"type":"integer"}},"bands_present":{"type":"integer"},"bands_possible":{"type":"integer"}}},"weekday_weekend_split":{"type":"object","description":"Events in the window by local day of week.","properties":{"weekday":{"type":"integer"},"weekend":{"type":"integer"}}},"daytime_evening_split":{"type":"object","description":"Events in the window by local start hour; evening is 16:00 or later.","properties":{"daytime":{"type":"integer"},"evening":{"type":"integer"}}}}},"ActivityEvidence":{"type":"object","description":"One of the ten nearest items — five nearest dated things and five nearest places, merged by distance. Show these, do not paraphrase them.","required":["listing_id","type","name","distance_m"],"properties":{"listing_id":{"type":"string","format":"uuid","description":"Fetch the full row from `/v1/{type}s/{listing_id}`."},"type":{"$ref":"#/components/schemas/ListingType"},"name":{"type":"string"},"distance_m":{"type":"integer"},"next_at":{"type":["string","null"],"format":"date-time","description":"When it next happens. Null for a place."},"type_hint":{"$ref":"#/components/schemas/PlaceTypeHintNullable"},"is_free":{"type":["boolean","null"]}}},"PlaceTypeHintNullable":{"type":["string","null"],"enum":["play_space","museum","park","library","theater","sports_facility","farm","restaurant","other",null]},"Activity":{"type":"object","required":["point","radius_m","days","components","activity_score","summary","evidence"],"properties":{"point":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"radius_m":{"type":"integer"},"days":{"type":"integer"},"metro":{"type":["string","null"]},"generated_at":{"type":"string","format":"date-time"},"components":{"$ref":"#/components/schemas/ActivityComponents"},"score_parts":{"type":"object","description":"Diagnostic scoring detail. Present only to internal keys that\nrequest diagnostics.\n","properties":{"programming":{"type":"number"},"places":{"type":"number"},"recurring":{"type":"number"},"access":{"type":"number"},"breadth":{"type":"number"}}},"activity_score":{"type":"number","minimum":0,"maximum":100,"description":"0-100, absolute and comparable across metros and over time."},"percentile":{"type":["integer","null"],"minimum":0,"maximum":100,"description":"Where this score falls against the metro's reference distribution. Null until enough comparison data is available."},"percentile_basis":{"type":"string","description":"Diagnostic context for the percentile. Present only to internal\nkeys that request diagnostics.\n"},"summary":{"type":"string","description":"One sentence a listing page can print as-is."},"evidence":{"type":"array","items":{"$ref":"#/components/schemas/ActivityEvidence"}},"resolved_address":{"type":["object","null"],"description":"Present only when the request used `address`. Null for the `lat`/`lng` form.","properties":{"query":{"type":"string"},"formatted":{"type":["string","null"]},"place_id":{"type":["string","null"]},"source":{"type":"string","enum":["cache","geocoder"]}}}}},"ActivityResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"$ref":"#/components/schemas/Activity"},"meta":{"type":"object","properties":{"metro":{"type":"string"},"radius_m":{"type":"integer"},"days":{"type":"integer"},"generated_at":{"type":"string","format":"date-time"}}}}},"NearbyItem":{"type":"object","required":["listing_id","type","name","distance_m"],"properties":{"listing_id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/ListingType"},"name":{"type":"string"},"slug":{"type":["string","null"]},"distance_m":{"type":"integer","description":"Great-circle metres from the requested point."},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"next_at":{"type":["string","null"],"format":"date-time"},"is_free":{"type":"boolean"},"type_hint":{"$ref":"#/components/schemas/PlaceTypeHintNullable"},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"}},"age_bands":{"type":"array","items":{"type":"string","enum":["baby","toddler","young_kids","bigger_kids"]}},"source_url":{"type":["string","null"]}}},"NearbyList":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NearbyItem"}},"meta":{"type":"object","required":["limit","count","has_more"],"properties":{"metro":{"type":"string"},"point":{"type":"object","properties":{"lat":{"type":"number"},"lng":{"type":"number"}}},"radius_m":{"type":"integer"},"applied_filters":{"type":"object","description":"The radius and types used, whether sent or defaulted.","properties":{"radius_m":{"type":"integer"},"types":{"type":"array","items":{"type":"string"}}}},"defaults_applied":{"$ref":"#/components/schemas/DefaultsApplied"},"types":{"type":"array","items":{"type":"string","enum":["event","class","camp","place"]}},"limit":{"type":"integer"},"count":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]},"generated_at":{"type":"string","format":"date-time"}}}}},"ResolvedLocation":{"type":"object","description":"The resolved location for the address. Render `formatted_address`: the same address string can resolve two ways (`605 Glen Ave` resolves to both Moorestown NJ and Philadelphia PA, 14.6 km apart), and a consumer that shows only results cannot tell which it got.","required":["lat","lng","source"],"properties":{"query":{"type":["string","null"],"description":"The `address` as sent, or `null` for the lat/lng form."},"formatted_address":{"type":["string","null"],"description":"What the address was resolved to. Null for the lat/lng form — there is nothing to echo."},"place_id":{"type":["string","null"]},"source":{"type":"string","enum":["cache","geocoder","address_index","coordinates"],"description":"How this location was resolved. `coordinates` means you sent\n`lat`/`lng` directly and no resolution was needed. `cache`,\n`geocoder`, and `address_index` each name a different way an\n`address` was resolved into coordinates. A single request uses\none resolution path only.\n"},"lat":{"type":"number"},"lng":{"type":"number"},"neighborhood":{"type":["object","null"],"description":"Nearest neighbourhood **centroid**, not a polygon containment — there is no neighbourhood boundary data. Check `centroid_distance_m` before trusting it: a point in Wayne matches King of Prussia at 5,416 m, which the number makes obvious.","properties":{"name":{"type":"string"},"slug":{"type":"string"},"centroid_distance_m":{"type":"integer"},"match":{"type":"string","enum":["nearest_centroid"]}}},"metro":{"type":["string","null"]},"metro_name":{"type":["string","null"]},"timezone":{"type":"string"}}},"ActivityHeader":{"type":"object","description":"The `/activity` number, included as the header on these results.","properties":{"score":{"type":["number","null"],"description":"0-100, absolute and comparable between metros and over time."},"percentile":{"type":["integer","null"],"description":"Against this metro's reference grid. Null until that reference grid has been computed for the metro."},"percentile_basis":{"type":["string","null"],"description":"Why `percentile` is what it is, including why it is null.\nPresent only to internal keys that request diagnostics.\n"},"summary":{"type":["string","null"],"description":"One sentence a listing page can print."},"score_parts":{"type":"object","description":"Present only to internal keys that request diagnostics.\n","properties":{"programming":{"type":"number"},"places":{"type":"number"},"recurring":{"type":"number"},"access":{"type":"number"},"breadth":{"type":"number"}}},"components":{"type":"object","description":"The raw counts behind the score."}}},"AroundRankingTerms":{"type":"object","description":"Reserved internal diagnostics. Customer keys cannot request this block.","additionalProperties":true},"AroundItem":{"type":"object","required":["listing_id","type","name","distance_m","walk_minutes","score"],"properties":{"listing_id":{"type":"string","format":"uuid"},"type":{"$ref":"#/components/schemas/ListingType"},"name":{"type":"string"},"slug":{"type":["string","null"]},"description":{"type":["string","null"],"description":"Truncated to 400 characters."},"distance_m":{"type":"integer","description":"Great-circle metres from the resolved point."},"walk_minutes":{"type":"integer","minimum":1,"description":"`max(1, ceil(distance_m / 80))` — 80 m/min, a parent with a buggy. Never 0, so a listing at the searched address itself reads \"1 min\". Straight-line, so a lower bound: no street network is consulted."},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"next_at":{"type":["string","null"],"format":"date-time","description":"The next date this row can be attended. Null for a place."},"next_local":{"type":["string","null"],"description":"The same instant as naive local wall-clock in the metro's zone."},"ends_at":{"type":["string","null"],"format":"date-time"},"is_free":{"type":"boolean"},"age_bands":{"type":"array","items":{"type":"string","enum":["baby","toddler","young_kids","bigger_kids"]}},"categories":{"type":"array","items":{"$ref":"#/components/schemas/ListingCategory"}},"type_hint":{"$ref":"#/components/schemas/PlaceTypeHintNullable"},"place":{"type":"object","description":"The place the row is held at, with the row's own address.","properties":{"id":{"type":["string","null"],"format":"uuid"},"street_address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zip":{"type":["string","null"]},"neighborhood":{"type":["string","null"]}}},"recurrence":{"type":["object","null"],"description":"Present when the row recurs at all. `meets_regularly` distinguishes a weekly/monthly rhythm from a run of a show.","properties":{"meets_regularly":{"type":"boolean"},"rrule":{"type":["string","null"]},"description":{"type":["string","null"]},"days":{"type":["array","null"],"items":{"type":"string"}},"schedule_type":{"type":["string","null"]}}},"enrollment":{"type":["object","null"],"description":"Class term and registration, or camp season and deadline. Null for events and places."},"registration_url":{"type":["string","null"]},"image_url":{"type":["string","null"]},"source_url":{"type":["string","null"]},"confidence":{"type":"number","minimum":0,"maximum":1},"source_status":{"$ref":"#/components/schemas/SourceStatus"},"score":{"type":"number","description":"Comparable within this group, in this query. Not across groups: a place takes the time and recurrence terms for free."},"rank":{"type":"integer"},"why":{"$ref":"#/components/schemas/AroundRankingTerms"},"also_in":{"type":"array","description":"The other groups this same row appears in. `happening_soon` and `recurring_programs` overlap on purpose.","items":{"type":"string","enum":["happening_soon","recurring_programs","classes_enrolling","camps","places"]}}}},"AroundGroup":{"type":"object","required":["total","returned","items"],"properties":{"total":{"type":"integer","description":"Matching rows in this group inside the whole circle, not just this page."},"returned":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Pass as `cursor` to continue this group: `\"<group>:<offset>\"`."},"items":{"type":"array","items":{"$ref":"#/components/schemas/AroundItem"}}}},"AroundResults":{"type":"object","description":"The five groups a family reads. Every group is always present, so an empty one is a statement rather than an omission — read it together with `coverage`.","properties":{"happening_soon":{"$ref":"#/components/schemas/AroundGroup"},"recurring_programs":{"$ref":"#/components/schemas/AroundGroup"},"classes_enrolling":{"$ref":"#/components/schemas/AroundGroup"},"camps":{"$ref":"#/components/schemas/AroundGroup"},"places":{"$ref":"#/components/schemas/AroundGroup"}}},"AroundFacets":{"type":"object","description":"Counts over every matching row in the circle, so a client can draw its filter controls without a second request.","properties":{"by_type":{"type":"object","additionalProperties":{"type":"integer"}},"by_age_band":{"type":"object","additionalProperties":{"type":"integer"}},"by_price":{"type":"object","properties":{"free":{"type":"integer"},"paid":{"type":"integer"}}},"free_share":{"type":["number","null"]},"by_distance_ring":{"type":"array","description":"**Cumulative**: `within_800m` includes everything inside 400 m, which is what a \"only show me ten minutes away\" control needs.","items":{"type":"object","properties":{"label":{"type":"string","enum":["within_400m","within_800m","within_1600m","within_radius"]},"max_m":{"type":"integer"},"count":{"type":"integer"}}}}}},"AroundCoverage":{"type":"object","description":"How many nearby rows this response **cannot** show. An empty group with `hidden_nearby > 0` means those rows are not visible to this endpoint, not that the area has nothing happening. Render it.","required":["hidden_nearby","unplaceable_in_metro","reason"],"properties":{"hidden_nearby":{"type":"integer","description":"Rows that would fall inside this exact circle if they had coordinates from their linked place. Computed per request, not a global disclaimer."},"hidden_nearby_by_group":{"type":"object","description":"Which group each hidden row would land in.","additionalProperties":{"type":"integer"}},"unplaceable_in_metro":{"type":"integer","description":"Rows with neither their own coordinates nor a located place, metro-wide — these rows cannot be placed, so they are not claimed to be near you."},"reason":{"type":"string","description":"A sentence a client can show the user verbatim."},"unplaceable_note":{"type":"string"}}},"AroundRanking":{"type":"object","description":"Reserved internal diagnostics. Customer keys cannot request this block.","additionalProperties":true},"AroundResponse":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"object","required":["location","results","facets","coverage"],"properties":{"location":{"$ref":"#/components/schemas/ResolvedLocation"},"activity":{"oneOf":[{"$ref":"#/components/schemas/ActivityHeader"},{"type":"null"}],"description":"`null` when nothing could be scored for this point —\nthe results below are still a complete answer, they just have\nno headline number. Render the groups and omit the header\nrather than treating it as a failure.\n"},"results":{"$ref":"#/components/schemas/AroundResults"},"facets":{"$ref":"#/components/schemas/AroundFacets"},"coverage":{"$ref":"#/components/schemas/AroundCoverage"},"ranking":{"$ref":"#/components/schemas/AroundRanking"}}},"meta":{"type":"object","required":["metro","radius_m","window","limit"],"properties":{"metro":{"type":"string"},"radius_m":{"type":"integer"},"window":{"type":"object","required":["from","to","timezone"],"description":"The resolved window as local calendar dates — the same shape `ListMeta.window` has, with `from` clamped to now.","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date","description":"Inclusive; defaulted to `from` + 30 days when not given."},"timezone":{"type":"string"}}},"applied_filters":{"type":"object","description":"The window, radius, confidence floor and types in effect, whether sent or defaulted, plus `ages` and `free` when given.","properties":{"radius_m":{"type":"integer"},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"min_confidence":{"type":"number"},"types":{"type":"array","items":{"type":"string"}},"ages":{"type":"array","items":{"type":"string"}},"free":{"type":"boolean"}}},"defaults_applied":{"$ref":"#/components/schemas/DefaultsApplied"},"filters":{"type":"object","properties":{"ages":{"type":["array","null"],"items":{"type":"string"}},"is_free":{"type":["boolean","null"]},"types":{"type":["array","null"],"items":{"type":"string"}},"min_confidence":{"type":"number"}}},"limit":{"type":"integer","description":"Per group."},"cursor_group":{"type":["string","null"],"description":"Set when a `cursor` narrowed this response to one group."},"matched_total":{"type":"integer","description":"Distinct rows inside the circle after filters, before grouping."},"generated_at":{"type":"string","format":"date-time"}}}}},"ListingLinks":{"type":"object","description":"Relative paths for this item and, when linked, its place and organization.","required":["self"],"properties":{"self":{"type":"string","description":"This item."},"place":{"type":"string","description":"Present when the item has a linked place."},"organization":{"type":"string","description":"Present when the item has a linked organization."}}},"PlaceLinks":{"type":"object","description":"Relative paths for this place, its organization when linked, and its child collections.","required":["self","events","classes","camps"],"properties":{"self":{"type":"string","description":"This place."},"organization":{"type":"string","description":"Present when the place has a linked organization."},"events":{"type":"string","description":"Events at this place — same as `?place_id=` on `/v1/{metro}/events`."},"classes":{"type":"string","description":"Classes at this place."},"camps":{"type":"string","description":"Camps at this place."}}},"OrganizationLinks":{"type":"object","description":"Relative paths for this organization's own resource and its child collections.","required":["self","events","classes","camps","places"],"properties":{"self":{"type":"string","description":"This organization."},"events":{"type":"string","description":"Events run by this organization."},"classes":{"type":"string","description":"Classes run by this organization."},"camps":{"type":"string","description":"Camps run by this organization."},"places":{"type":"string","description":"Places owned by this organization."}}}}}}