/v1/{metro}/searchall plansSearch every listing collection
Searches published, active listings in one metro. When semantic search is enabled, results match by meaning as well as keywords. Search applies the same visibility and filter rules as each list endpoint, so it never returns a listing that endpoint would hide. Results are ranked and paginated across collections. Recurring events use their next occurrence.
Show more
How words are matched. The query is read as plain words: quotes, a leading - and OR are not interpreted. Different forms of a word match each other (swim finds swimming), and a short list of closely related family-activity words also counts (pottery finds ceramics, baking finds cooking). Question and filler words (where can I, with, for, the) are ignored and never change a score. Words that only name the kind of listing (class, lessons, camp) never decide whether a listing matches; they only lift a listing that has them in its name.
Ages and audiences. An age in the query becomes an age filter: 5 year olds, ages 3-5, toddlers (1 to 3), baby (0 to 1) and teens (13 to 18). The band that was applied is echoed in meta.interpreted.age. When the query gives an age, listings whose stated ages cover it rank above listings with no stated ages; listings whose ages exclude it are left out. An explicit age or audience parameter always wins: the age in the words is then not applied, and meta.interpreted.age.overridden_by says which parameter won. Time and price words (tonight, saturday, morning, cheap) are not filters yet: they never decide a match and are listed in meta.ignored_words. Audience words (parents, kids, family) do not narrow the search when other words are present, and are listed in meta.ignored_words; a title that names them still ranks a little higher. A query made only of such words is never refused: Mommy and Me, kids and family search for those words as written. A query with nothing searchable at all (near me, where can I) returns 400.
How directly a result matches. Every result carries match. all_terms: every word you typed is in the listing's name or category, or is prominent in the opening of its description. related: every word is covered that way, but at least one only through a closely related word. partial: only some of your words, or all of them only mentioned in passing further down a description (food in a park concert that sells snacks). Inside a level, a name match ranks above a category match, which ranks above a description match. By default only all_terms and related are returned, so a count reflects real matches; send match=all_terms,related,partial (or match=partial alone) to include the loose ones. meta.match_counts says how many results there are at each level, whatever match you chose, so a client can say "17 direct, 36 related, 1,378 loose". Results are ordered so that all_terms come before related, and those before partial, unless you choose another sort.
score is an absolute 0 to 1 measure of how well one listing fits the words of the query. It is not scaled against the other results, so a weak best match no longer shows as 1, and the same listing gets the same score whatever else is returned. It is not a probability. snippet is a plain-text, unhighlighted excerpt of the listing's public description (or name when no description exists), at most 180 characters.
sort=relevance is the default. soonest orders dated results by their next occurrence (including recurring events), with places and undated items after them. nearest orders by distance and requires lat + lng or near_zip. newest orders by created_at. Every order breaks ties by score, then id; cursors are bound to the sort and ranking mode. If semantic availability changes between pages, the API returns 400 bad_request with details.reason: cursor_expired; restart the search without a cursor so results are never silently skipped.
curl -sS \
-H "X-API-Key: $TAILEND_API_KEY" \
"https://api.tailend.dev/v1/philadelphia/search?q=family%20story%20time"{
"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"
}
}