API reference
Four endpoints: a page of events, one event, and the two vocabularies needed to query them. Every one is a GET, every one needs the events:read scope, and every one is relative to https://api.locally-social.com/api/v1.
List events
Upcoming public events, soonest first. Cursor-paged. Only events at a visible venue with a public page are returned, so the count here will not match a raw corpus total.
Location
Three ways to say where, and the city composes with either of the others as an AND. The ZIP and the coordinate pair are both centres, so naming both is a 422.
- citystring
- City name or slug —
Charlotteorcharlotte. Must be sent withstate; one without the other is a422rather than a half-applied filter. - statestring
- Two-letter state code. Must be sent with
city. - zipcodestring
- Five digits. Resolves to the ZIP’s centroid and searches
radius_milesaround it — so this means “near this ZIP”, not “in it”, and will include a venue three blocks over the line. Not combinable withlat/lng. A well-formed ZIP loso holds no centroid for is a422. - latnumber
- −90 to 90. Send with
lng. - lngnumber
- −180 to 180. Send with
lat. - radius_milesnumber
- Applies to
zipcodeand tolat/lng. Defaults to15, caps at100. Ignored when the only location iscity/state, which is an administrative boundary rather than a centre.
Time and category
- starts_aftertimestamp
- ISO 8601. Defaults to now — the API is forward-looking, and a default that included last year would make the first call useless. Pass an explicit past instant to read history.
- starts_beforetimestamp
- ISO 8601. Exclusive upper bound on start time.
- updated_sincetimestamp
- ISO 8601. Only events whose row changed at or after this instant. A filter, not a change feed: it cannot tell you an event was deleted or stopped being public, and a row that changes while you are paging may be missed. Re-read a window you care about rather than relying on this to be exhaustive.
- categorystring
- A name or a slug from
/categories— both are accepted. An unknown value is a422naming the mistake, not a200with an empty page.
Paging
- limitinteger
- Rows per page. Defaults to
25, capped by tier (25 / 50 / 200). A larger value is clamped, not refused — asking for more than a tier gives still answers, with a cursor to continue. - cursorstring
- The
next_cursorfrom a previous response, unchanged. Opaque: its contents will change, so parsing it is the one way to be broken by a release that kept every compatibility promise. A cursor loso did not issue is a422.
curl "https://api.locally-social.com/api/v1/events?city=Charlotte&state=NC&category=comedy&limit=50" \
-H "Authorization: Bearer $LOSO_API_KEY"{
"data": [
{
"id": "9f1c6b4e-2a71-4d58-9c33-0e5a7b812d04",
"title": "Thursday Night Trivia",
"description": "Six rounds, teams of up to six, no phones.",
"start_at": "2026-11-05T23:30:00Z",
"end_at": null,
"time_tbd": false,
"categories": ["Trivia & Games"],
"is_recurring": true,
"recurrence_pattern": "Weekly on Thursday",
"price": 0,
"ticket_url": null,
"image_url": "https://cdn.locally-social.com/events/9f1c6b4e.jpg",
"is_sold_out": false,
"url": "https://locally-social.com/events/charlotte-nc/thursday-night-trivia-9f1c6b4e2a71",
"updated_at": "2026-11-01T14:02:11Z",
"venue": {
"id": "c4e81a92-7f30-4b6d-85a1-2d9e03f7b418",
"name": "Selwyn Avenue Taproom",
"address": "2801 Selwyn Ave",
"city": "Charlotte",
"state": "NC",
"neighborhood": "Myers Park",
"latitude": 35.1823,
"longitude": -80.8471
}
}
],
"next_cursor": "MjAyNi0xMS0wNVQyMzozMDowMCswMDowMHw5ZjFjNmI0ZQ"
}There is no total. Counting the match set costs a second scan on every page and a cursor API does not need one — page until next_cursor comes back null. A count that is only approximately right is worse than none.
Retrieve an event
One event by id, including one that has already happened — an id from last week reads “this happened” rather than a 404 that cannot be told apart from an event loso never had.
- event_iduuidrequired
- Path parameter. The
idfrom any listing response.
curl "https://api.locally-social.com/api/v1/events/9f1c6b4e-2a71-4d58-9c33-0e5a7b812d04" \
-H "Authorization: Bearer $LOSO_API_KEY"{
"id": "9f1c6b4e-2a71-4d58-9c33-0e5a7b812d04",
"title": "Thursday Night Trivia",
"description": "Six rounds, teams of up to six, no phones.",
"start_at": "2026-11-05T23:30:00Z",
"end_at": null,
"time_tbd": false,
"categories": ["Trivia & Games"],
"is_recurring": true,
"recurrence_pattern": "Weekly on Thursday",
"price": 0,
"ticket_url": null,
"image_url": "https://cdn.locally-social.com/events/9f1c6b4e.jpg",
"is_sold_out": false,
"url": "https://locally-social.com/events/charlotte-nc/thursday-night-trivia-9f1c6b4e2a71",
"updated_at": "2026-11-01T14:02:11Z",
"venue": {
"id": "c4e81a92-7f30-4b6d-85a1-2d9e03f7b418",
"name": "Selwyn Avenue Taproom",
"address": "2801 Selwyn Ave",
"city": "Charlotte",
"state": "NC",
"neighborhood": "Myers Park",
"latitude": 35.1823,
"longitude": -80.8471
}
}List categories
Every value the category filter accepts, with a count of upcoming events behind each. A category with nothing behind it is listed at zero rather than omitted, so this is a stable vocabulary to build a filter UI from.
Not paged, and not fenced on a trial key: the counts cover the full corpus on every tier, so the vocabulary tells you what live access covers before you have it.
curl "https://api.locally-social.com/api/v1/categories" \
-H "Authorization: Bearer $LOSO_API_KEY"[
{ "name": "Arts & Culture", "slug": "arts-culture", "upcoming_event_count": 48 },
{ "name": "Beer / Brewery", "slug": "beer-brewery", "upcoming_event_count": 112 },
{ "name": "Comedy", "slug": "comedy", "upcoming_event_count": 31 },
{ "name": "Trivia & Games", "slug": "trivia-games", "upcoming_event_count": 96 }
]- namestring
- The value that appears in an event’s
categoriesarray. Accepted by?category=. - slugstring
- URL-safe form, also accepted by
?category=. - upcoming_event_countinteger
- Events upcoming in this category, corpus-wide.
List cities
Cities with upcoming coverage, deepest first. This is the honest answer to “where does loso have data” — and the right place to look before sending a city/state pair.
Not paged, and not fenced on a trial key.
curl "https://api.locally-social.com/api/v1/cities" \
-H "Authorization: Bearer $LOSO_API_KEY"[
{ "city": "Charlotte", "state": "NC", "upcoming_event_count": 1842 },
{ "city": "Raleigh", "state": "NC", "upcoming_event_count": 503 }
]The event object
Every field an event carries. A field may be added in a future release; none is renamed, removed or re-typed within v1.
- iduuid
- Stable. Never reused.
- titlestring
- Never null.
- descriptionstring | null
- Null where the source published none. Length is not bounded.
- start_attimestamp
- UTC, always. Local time is the venue’s — use
venueto work out where that is. Never null. - end_attimestamp | null
- Null when the organiser did not state one, which is most events. Not a duration of zero — rendering it as an end time equal to the start is the common mistake here.
- time_tbdboolean
- True when only the date is known.
start_atthen carries a placeholder time that must not be displayed as the start. Check this before formatting a clock time. - categoriesstring[]
- Values from
/categories. Empty when unclassified — not null. - is_recurringboolean
- Whether this event is one occurrence of a repeating series.
- recurrence_patternstring | null
- Human-readable, e.g.
Weekly on Thursday. For display, not for parsing — it is not an RRULE and its wording is not part of the contract. - pricenumber | null
- USD. Three states, not interchangeable: a number is the price,
0means free, andnullmeans no price was published — which is not the same as free and must not be rendered as it. - ticket_urlstring | null
- Where to buy, when the source published a link. Points off-site as often as not.
- image_urlstring | null
- Cover art. Null is common.
- is_sold_outboolean
- Whether the source reports no remaining tickets.
- urlstring
- The event’s page on locally-social.com. Never null — an event with no page is excluded from the listing rather than served with a URL that would 404.
- updated_attimestamp
- When the row last changed. Usable with
updated_sinceto skip events you already hold. - venueobject | null
- Where it happens, nested rather than referenced — see below. Null only when loso has neither a venue row nor a name.
The venue object
Nested inside the event, never fetched separately. A caller rendering a listing needs the venue name and coordinates on every row, and one request per venue would turn one page into fifty calls against a per-minute limit. There is no venue collection.
- iduuid | null
- Null for a venue loso knows only as a name — a flyer that says “The Backroom” and nothing more. The name is still returned; there is simply no venue resource behind it. Handle this: it is common, and it is the case a happy-path sample will not show you.
- namestring | null
- The venue's name, or the name off the flyer.
- addressstring | null
- Short form, e.g. `2801 Selwyn Ave`.
- citystring | null
- Parsed from the address.
- statestring | null
- Two-letter code.
- neighborhoodstring | null
- Where loso has one. Often null outside Charlotte.
- latitudenumber | null
- Null together with `longitude` for an unlocated venue.
- longitudenumber | null
- See `latitude`.
{
"id": "1b7f20c8-5d49-4e02-a6f1-8c3b5e7d9011",
"title": "Backlot Night Market",
"start_at": "2026-11-08T21:00:00Z",
"end_at": null,
"time_tbd": false,
"categories": ["Markets & Shopping"],
"is_recurring": false,
"recurrence_pattern": null,
"price": null,
"ticket_url": null,
"image_url": null,
"is_sold_out": false,
"url": "https://locally-social.com/events/charlotte-nc/backlot-night-market-1b7f20c85d49",
"updated_at": "2026-11-02T09:41:55Z",
"venue": {
"id": null,
"name": "The Backlot",
"address": null,
"city": null,
"state": null,
"neighborhood": null,
"latitude": null,
"longitude": null
}
}Google-derived venue attributes — rating, review count, price level, business status, photos, the Places type taxonomy — are deliberately absent, as is the URL loso crawled an event from.