Skip to content

Changelog

Changelog

Customer-facing changes to the Tailend API, newest first.

What changed in the Tailend API, for people calling it. Additive changes (new optional parameters, new fields) can ship at any time; see Audience & versioning for what v1 promises not to break.

changed

Try any request from the API reference

Every endpoint in the API reference now has a Try it panel. Without a key it shows a sample response; paste a key to send the request live and see the status, headers and body. The standalone playground is retired, and its links forward to the reference.

added

A status page

https://api.tailend.dev/status is now a page: overall status, API and docs status, data freshness per city, 90-day API uptime and past incidents. Programs keep getting JSON from the same URL (any Accept other than text/html), and /status.json is the JSON explicitly. Both refresh once a minute.

  • JSON: meta gains status, components, uptime and incidents.
  • Changed: meta.unavailable[] entries are now { what, reason } in plain words, and last_successful_ingest.source describes where the time comes from instead of naming internal objects.
added

Teams on events

Events carry teams: the local pro sports teams an event is built around (watch parties, game-day themed events, team or mascot appearances). It is always an array, empty when none. Values today: eagles, phillies, sixers, flyers, union.

cURL
curl -G -H "X-API-Key: $TAILEND_API_KEY" --data "team=eagles,phillies" \
  https://api.tailend.dev/v1/philadelphia/events
  • team= works on /v1/{metro}/events, the events routes under places and organizations, /events/calendar and /search.
  • One value or a comma-separated list, matching any.
  • An unknown value is a 400 that lists the allowed ones.
  • On /search, team= limits the results to events.
  • Available on every plan.
changed

q also finds organization and place names

q on /v1/{metro}/events, /classes, /camps, /places and /search now also matches the name of the organization behind a listing and the place it happens at, tolerating spacing, punctuation and small typos. Searching for an organization's name now finds its listings even when their own names do not mention it.

added

Related listings with include=related

GET /v1/events/{id}, /v1/classes/{id} and /v1/camps/{id} (and their slug forms) accept include=related, which adds related: {similar, from_organization, at_place}: up to six compact cards each, so a listing page gets its "more like this" rows in one request.

  • Related cards are listings the list endpoints would also return to your key.
  • An add-on entitled like include=source (partner plans, or granted on a standard key).
  • 400 on lists, search and places.
  • If a list cannot be produced it comes back empty with a related_unavailable notice.

See Shaping responses.

changed

Adult-only listings report adults in ages.audience

A listing flagged as adult-only content now reports adults in ages.audience as well as audience, whatever its source page's wording. Lists already left these out by default.

fixed

ages.min is null when ages are not stated

ages.min is null when a listing does not state its ages, instead of 0. A stated 0 (for example 0 to 5) is unchanged, and age= still keeps listings that do not state their ages.

added

Event calendar counts

GET /v1/{metro}/events/calendar?from=…&to=… returns, for every date in a window of up to 62 days, how many occurrences start that day, how many are free, and a count per category. The counts match the expanded event list exactly.

cURL
curl -G -H "X-API-Key: $TAILEND_API_KEY" \
  --data "from=2026-11-01" --data "to=2026-11-30" \
  https://api.tailend.dev/v1/philadelphia/events/calendar

With include=forecast on eligible paid plans, today and the next seven days also carry a day forecast.

added

One item per occurrence with occurrences=expand

GET /v1/{metro}/events?occurrences=expand&from=…&to=… lists one item per occurrence, for calendar views: a recurring event appears on every day it happens in the window (up to 31 days), each item carrying an occurrence block with its own start, end and position in the series. Local times hold across daylight-saving changes. Without occurrences=expand, /events is unchanged.

added

Fetch listings by id with ids=

/v1/{metro}/events, /classes, /camps and /places accept ids= (up to 100 listing ids, comma-separated) to fetch specific listings in one call. Results come back in the order given, with no date window and no paging. Ids that are unknown, of another type, or no longer active are listed in meta.missing_ids.

added

Classes starting in a date range

/v1/{metro}/classes accepts starts_from and starts_to (local dates, inclusive, either alone) to keep classes whose term starts in the range, for "classes starting this week". For programs with sections, any section starting in the range matches, and sections are returned whole.

added

Indoor, outdoor and sensory-friendly facts

Events and classes carry is_indoor, is_outdoor, good_for_rainy and is_sensory_friendly, facts about the place they happen at; places carry is_sensory_friendly. null means the place does not say.

  • Filter with indoor=, outdoor= and sensory=.
  • A listing whose value is unknown matches neither true nor false.
added

Classes with sections

Classes can list their variants as sections (days and times, age groups, terms, each with its own tuition and availability).

  • Class filters for weekday, age, time, dates and price match a single section at once.
  • openings=true keeps programs with open seats.
  • Programs published as several listings appear as one card, with the others under sessions; expand=sessions returns every class on its own.
  • Section changes show up as updates in /v1/changes and the per-listing history.

See Classes with sections.

added

Event forecasts with include=forecast

Events can opt into include=forecast on eligible paid plans. Timed US events in the next seven days receive either event-hour detail or a local-day summary. Ineligible events omit the field; temporary availability problems are reported through notices[]. See Shaping responses.

added

Facets

Add facets= to an events, classes, camps or places list to get counts by category, weekday, time_block, price_band, age_band and organization over every listing that matches the filters, not just the page. limit=0 returns the counts alone. Available on every plan and counted as one request.

cURL
curl -G -H "X-API-Key: $TAILEND_API_KEY" \
  --data "facets=category,weekday" --data "limit=0" \
  https://api.tailend.dev/v1/philadelphia/events

See Market overview with facets.

added

Responses say which filters they used

Every list response (events, classes, camps, places, search, nearby and around) carries meta.applied_filters, the value in effect for each filter, and meta.defaults_applied, the names that came from a default rather than your request. A smaller-than-expected result can now be explained from the response itself.

  • Events still cover the next 30 days by default.
  • min_confidence still defaults to 0.7 (0.5 on places).
  • adults audiences are still left out, echoed as audience: ["not_adults"], a value you can send back as audience=not_adults.
changed

Search understands word forms, related words and ages

On GET /v1/{metro}/search:

  • swim finds swimming, and closely related family-activity words count: pottery finds ceramics, baking finds cooking.
  • Question and filler words (where can I, with, for) no longer pull in unrelated listings or change a score.
  • 5 year olds, ages 3-5, toddlers, baby and teens narrow by age; the band applied is echoed in meta.interpreted. An age or audience you send yourself wins.
  • Time and price words (tonight, saturday, cheap) are not filters yet; they are listed in meta.ignored_words.

See Search.

added

Match levels on search results

Each search result carries match: all_terms, related or partial. The match parameter selects which levels are returned (loose partial matches are now opt-in), and meta.match_counts counts every level whatever you selected. Search cursors from before this change are no longer accepted; restart the search without the cursor.

changed

Search score is absolute

score on search results was scaled so the best result in each search read

  1. It is now a 0 to 1 measure of how well one listing fits the query's words,

the same whatever else is returned, and comparable between queries.

changed

Finding an organization works the way people type

On GET /v1/{metro}/organizations, q finds a business by its name, its website address or a pasted URL, ignoring casing, punctuation, spacing and endings such as LLC, Inc, & Co and .com. design gym, Design Gym and designgym.com all find designgym.co, and a small typo still finds it.

  • Results carry score (0 to 1) and match (exact_name, exact_domain, name, domain or fuzzy), best match first.
  • A query of only the, and, llc, .com and the like returns an empty list with a meta.hint.
  • Organization-search cursors from before this change are no longer accepted.

See Finding a business.

changed

website_url is filled in more often

When an organization has no website recorded, website_url now shows the address of the site the organization itself runs, if we have one.

changed

Clearer meaning for class fields a provider may not state

The descriptions for program.adult_participation, term.total_classes, tuition.drop_in_price, tuition.trial_price, tuition.trial_notes, registration.spots_remaining and registration.has_spots_available now say what null means: not stated by the source, never "no". The response shape is unchanged.

added

Unified listing search

GET /v1/{metro}/search searches events, classes, camps and places with the same visibility and filter rules as the individual list endpoints.

cURL
curl -G -H "X-API-Key: $TAILEND_API_KEY" --data-urlencode "q=story time" \
  https://api.tailend.dev/v1/philadelphia/search

Very broad queries may set meta.capped: true; add filters or a more specific q to narrow them. See Search.

added

Recurring events listed by their next occurrence

A recurring event's occurrence.next_starts_at and next_starts_local give the next live date, and from/to windows on GET /v1/{metro}/events include a series by that next occurrence rather than only its original start date. A series with no more occurrences stops appearing in lists; its permalink still resolves by id or slug. See Recurring events.

added

Plan-level access for premium features

A key's effective entitlement is its plan's defaults plus whatever is granted on the key itself. A premium endpoint without the entitlement answers 403 feature_not_in_plan, distinct from include_not_permitted. include=source follows the same rule. Both 403 include_not_permitted and its include_mode=lenient notice now carry an upgrade link. See Plans & access.

changed

Places default to min_confidence=0.5

Events, classes and camps keep the 0.7 default. Pass min_confidence=0.7 on a places call for the previous behaviour.

fixed

Events with no date return null, not an empty string

starts_at and starts_local are null when an event has no date, and a new has_date boolean tells you which case you're in without parsing either field. If your code assumed starts_at was always a non-empty string, treat null the way you'd already have treated "".

fixed

Listing version history shows public change facts only

Each item from GET /v1/listings/{id}/versions contains changed_at, a closed kind, and public field names only. Raw changed values are no longer returned.

fixed

source.verification.status lists its real values

With include=source, the documented values are clear, changed, flagged, unverifiable, unreachable and gone. Two values that never occur were removed.

changed

Vocabulary cleanup before launch

organizer is organization everywhere, a "venue" is a place, include=provenance is include=source, distances are metres only, and GET /v1/{metro}/vitality is GET /v1/{metro}/activity.

added

Audience on every listing

Every event, class, camp and place carries audience (kids, families, teens, adults, all_ages). Adult-only content is excluded by default on list endpoints; pass audience=all to include it.

added

Relationship routes

List a place's or organization's events, classes and camps directly (/v1/places/{id}/events, and similarly for organizations), with every other list parameter still available.

added

Seasons, links and images

  • traits.seasons on events, classes and camps, with a matching season= filter.
  • links on every resource: relative paths to the resource and its related collections.
  • images on places: more photos beyond image_url.
changed

Lean default responses

Every resource carries a flat confidence and verified_at. Where the data came from, and detailed verification status, moved behind include=source; add include_mode=lenient to get a 200 instead of a 403 when your key isn't entitled.

changed

New API key format

Keys are issued as tl_<prefix>_<secret>. Existing keys keep working.