Developers
Free Asheville Events API
AVL GO collects upcoming events in Asheville, NC and nearby Western North Carolina towns from venue calendars, ticketing sites, Meetup, libraries, local government calendars and community listings, and serves them through a free, read-only JSON API. No API key or sign-up needed.
Quick start
Everything goes through one endpoint, https://www.avlgo.com/api/export/json. Add format=compact for small, paginated records; without it you get the full export, every matching upcoming event with every field in one response.
curl "https://www.avlgo.com/api/export/json?format=compact&dateFilter=today&limit=20"How do I get today’s events in Asheville as JSON?
Ask for dateFilter=today. locations=asheville keeps events in Asheville and at known Asheville venues; leave it off to include nearby towns. Today means the current calendar day in Eastern time, including events that started earlier in the day. limit=3 keeps this example short; it goes up to 100.
https://www.avlgo.com/api/export/json?format=compact&dateFilter=today&locations=asheville&limit=3{
"count": 3,
"generated": "2026-10-02T16:00:00.000Z",
"timezone": "America/New_York",
"events": [
{
"id": "6880f252-0fff-43d8-937b-b37cd7e1e0ac",
"title": "Sunset Yoga in the Park",
"startDate": "2026-10-02T18:00:00-04:00",
"location": "Pack Square Park, Asheville, NC",
"price": "Free",
"aiSummary": "An all-levels outdoor yoga class at sunset. Bring a mat and water.",
"url": "https://www.avlgo.com/events/sunset-yoga-in-the-park-2026-10-02-6880f2"
},
{
"id": "49735df5-ae1b-405b-a122-a0cddce00744",
"title": "Old-Time String Band Night",
"startDate": "2026-10-02T19:00:00-04:00",
"location": "River Arts District, Asheville, NC",
"price": "$15",
"aiSummary": "Local old-time and bluegrass string bands play two sets of traditional mountain music.",
"url": "https://www.avlgo.com/events/old-time-string-band-night-2026-10-02-49735d"
},
{
"id": "4b437a18-b555-4852-9c39-5c307346dff8",
"title": "Pub Trivia",
"startDate": "2026-10-02T19:30:00-04:00",
"location": "Downtown Asheville, NC",
"price": null,
"aiSummary": null,
"url": "https://www.avlgo.com/events/pub-trivia-2026-10-02-4b437a"
}
],
"nextCursor": "MjAyNi0xMC0wMlQyMzozMDowMC4wMDAwMDBaXzRiNDM3YTE4LWI1NTUtNDg1Mi05YzM5LTVjMzA3MzQ2ZGZmOA",
"hasMore": true
}What free events are happening this weekend?
dateFilter=weekend covers Friday through Sunday of this week, or what is left of the current weekend. priceFilter=confirmedFree keeps events the source lists as free; priceFilter=free also includes events with no listed price, which are often free (see prices).
https://www.avlgo.com/api/export/json?format=compact&dateFilter=weekend&locations=asheville&priceFilter=confirmedFree&limit=10{
"id": "b8313e2e-13ee-49a0-acb3-3495664b8c1f",
"title": "Pollinator Garden Volunteer Day",
"startDate": "2026-10-04",
"location": "West Asheville Park, Asheville, NC",
"price": "Free",
"aiSummary": "Volunteers weed, mulch and plant native pollinator species. Tools are provided.",
"url": "https://www.avlgo.com/events/pollinator-garden-volunteer-day-2026-10-04-b8313e"
}Where can I find live music?
Filter by tag with tagsInclude. Tags are exact and case-sensitive; list several with commas to match any of them (tagsInclude=Live%20Music,Comedy), and use tagsExclude to drop some. Tags are assigned by AI after an event is collected, so a brand-new listing may not have any yet.
https://www.avlgo.com/api/export/json?format=compact&tagsInclude=Live%20Music&limit=10{
"id": "49735df5-ae1b-405b-a122-a0cddce00744",
"title": "Old-Time String Band Night",
"startDate": "2026-10-02T19:00:00-04:00",
"location": "River Arts District, Asheville, NC",
"price": "$15",
"aiSummary": "Local old-time and bluegrass string bands play two sets of traditional mountain music.",
"url": "https://www.avlgo.com/events/old-time-string-band-night-2026-10-02-49735d"
}The main tags:
Live MusicComedyTheater & FilmDanceTriviaOpen MicKaraokeDiningBeerWine & SpiritsArtCraftsFitnessSportsWellnessSpiritualMeditationOutdoorsToursGamingEducationTechBook ClubMuseum ExhibitionFamilyDatingNetworkingNightlifeLGBTQ+PetsCommunityCivicVolunteeringSupport GroupsHolidayMarkets
Events can also carry more specific tags, like Bluegrass, which filter the same way. The full export shows each event’s tags.
How do I search for events?
search is a case-insensitive substring match against the title, description, organizer and location. Separate alternatives with commas: search=jazz,blues returns events that mention either word. Tags and AI summaries are not searched, so combine search with tagsInclude when you want both.
https://www.avlgo.com/api/export/json?format=compact&search=jazz,blues&limit=10{
"id": "54da8fc2-9773-4bb2-9201-8d00018f0e7e",
"title": "Late-Night Jazz Trio",
"startDate": "2026-10-02T21:00:00-04:00",
"location": "Haywood Rd, West Asheville, NC",
"price": "$10 - $20",
"aiSummary": "A jazz trio plays standards and originals in a late-night listening-room set.",
"url": "https://www.avlgo.com/events/late-night-jazz-trio-2026-10-02-54da8f"
}How do I choose specific dates?
Use dateFilter=custom with dateStart and, optionally, dateEnd, both YYYY-MM-DD in Eastern time. dateEnd is inclusive; without it you get dateStart alone. To pick days of the week instead, use dateFilter=dayOfWeek&days=5,6 (0 is Sunday), and narrow by part of the day with times=evening.
https://www.avlgo.com/api/export/json?format=compact&dateFilter=custom&dateStart=2026-10-02&dateEnd=2026-10-04&limit=10{
"id": "8b701ee6-49d6-4647-b87c-5d00e3ba29a0",
"title": "Blues Jam",
"startDate": "2026-10-03T20:00:00-04:00",
"location": "Black Mountain, NC",
"price": "$5 - $10",
"aiSummary": "An open blues jam where a house band backs guest players.",
"url": "https://www.avlgo.com/events/blues-jam-2026-10-03-8b701e"
}How do I retrieve the next page?
Repeat the request with cursor set to the nextCursor you got back, until hasMore is false; the paging rules cover the details. This continues the first example on this page:
https://www.avlgo.com/api/export/json?format=compact&dateFilter=today&locations=asheville&limit=3&cursor={nextCursor}{
"count": 1,
"generated": "2026-10-02T16:00:00.000Z",
"timezone": "America/New_York",
"events": [
{
"id": "54da8fc2-9773-4bb2-9201-8d00018f0e7e",
"title": "Late-Night Jazz Trio",
"startDate": "2026-10-02T21:00:00-04:00",
"location": "Haywood Rd, West Asheville, NC",
"price": "$10 - $20",
"aiSummary": "A jazz trio plays standards and originals in a late-night listening-room set.",
"url": "https://www.avlgo.com/events/late-night-jazz-trio-2026-10-02-54da8f"
}
],
"nextCursor": null,
"hasMore": false
}A loop that collects every event for a weekend:
const base = 'https://www.avlgo.com/api/export/json?format=compact&dateFilter=weekend&limit=20';
const events = [];
let url = base;
while (url) {
const page = await fetch(url).then((res) => res.json());
events.push(...page.events); // a page can be empty while hasMore is true
url = page.hasMore ? `${base}&cursor=${encodeURIComponent(page.nextCursor)}` : null;
}How do I get full records or Markdown?
Leave out format (or send format=full) to get every matching upcoming event with all fields: description, source, organizer, ZIP code, tags, scores and timestamps. Full mode is not paginated, so limit and cursor are ignored. Two fields differ from compact mode: startDate is a UTC timestamp (see dates and time zone), and url is the original source listing rather than the AVL GO page. The OpenAPI spec lists every field and its type.
https://www.avlgo.com/api/export/json?dateFilter=today&locations=asheville&tagsInclude=Live%20MusicExample response
{
"count": 1,
"generated": "2026-10-02T16:00:00.000Z",
"events": [
{
"id": "49735df5-ae1b-405b-a122-a0cddce00744",
"sourceId": "1234567890123",
"source": "EVENTBRITE",
"title": "Old-Time String Band Night",
"description": "Two sets of old-time and bluegrass from local string bands. All ages; doors at 6:30 PM.",
"startDate": "2026-10-02T23:00:00.000Z",
"location": "River Arts District, Asheville, NC",
"zip": "28801",
"organizer": "Blue Ridge String Collective",
"price": "$15",
"url": "https://www.eventbrite.com/e/old-time-string-band-night-tickets-1234567890123",
"imageUrl": null,
"tags": [
"Live Music",
"Bluegrass",
"Old Time"
],
"aiSummary": "Local old-time and bluegrass string bands play two sets of traditional mountain music.",
"interestedCount": null,
"goingCount": null,
"favoriteCount": 4,
"score": 17,
"scoreRarity": 5,
"scoreUnique": 6,
"scoreMagnitude": 6,
"scoreReason": "A regular local jam: modest in scale, but rooted in Appalachian music.",
"scoreAshevilleWeird": 6,
"scoreSocial": 7,
"recurringType": null,
"recurringEndDate": null,
"timeUnknown": false,
"createdAt": "2026-09-20T12:15:00.000Z",
"updatedAt": "2026-09-30T18:20:00.000Z",
"lastSeenAt": "2026-10-01T22:00:00.000Z"
}
]
}The Markdown export takes the same filters (not format, limit or cursor) and returns a readable list that links to the source listings, with descriptions cut to 500 characters. Its search treats the whole value as one phrase, commas included.
https://www.avlgo.com/api/export/markdown?dateFilter=today&locations=asheville&tagsInclude=Live%20MusicExample response
# Asheville Events
> Generated: 2026-10-02T16:00:00.000Z
> Total Events: 1
---
## [Old-Time String Band Night](https://www.eventbrite.com/e/old-time-string-band-night-tickets-1234567890123)
**Date:** Friday, October 2, 2026 at 7:00 PM
**Location:** River Arts District, Asheville, NC
**Organizer:** Blue Ridge String Collective
**Price:** $15
**Source:** EVENTBRITE
**Tags:** Live Music, Bluegrass, Old Time
Two sets of old-time and bluegrass from local string bands. All ages; doors at 6:30 PM.
---What does each compact field mean?
| Field | Type | Meaning |
|---|---|---|
| count | Type: integer | Number of events in this page (not the total match count). |
| generated | Type: string (UTC date-time) | When this response was built. See freshness. |
| timezone | Type: "America/New_York" | The time zone of every date in the response and every date filter. |
| events | Type: array | Matching events, ordered by start time. |
| nextCursor | Type: string or null | Pass back as cursor for the next page; null on the last page. |
| hasMore | Type: boolean | true while there may be more events. See paging. |
| events[].id | Type: string (UUID) | Stable AVL GO event id. |
| events[].title | Type: string | Event title as listed. |
| events[].startDate | Type: string | Eastern start time with its UTC offset (2026-10-02T19:00:00-04:00), or a date only (2026-10-02) when no start time was listed. See dates and time zone. |
| events[].location | Type: string or null | Venue and address text as the source listed it. |
| events[].price | Type: string or null | The source’s own price text, such as Free, $15 or $5 - $10; null when none is listed. See prices. |
| events[].aiSummary | Type: string or null | A one- or two-sentence AI-written summary; null until one has been written. |
| events[].url | Type: string (URL) | The event’s page on AVL GO, with full details and a link to the original listing. |
Which parameters can I use?
Every parameter is optional and works the same in compact and full mode. format, limit and cursor are JSON-only; the Markdown export takes the rest. An event has to pass every parameter you send; within a comma list, any one value counts. Except in search, times and days, list values are used exactly as sent, so put no space after a comma.
| Parameter | Values | What it does |
|---|---|---|
| format | Values: compact or full | Default full: every matching event with all fields, in one unpaginated response. compact: small, paginated records. Any other value returns 400. |
| limit | Values: Integer 1–100 (default 20) | Compact only: events per page. Any other value returns 400. Ignored in full mode. |
| cursor | Values: The last page’s nextCursor | Compact only: continue after the previous page (see paging). A malformed cursor returns 400. Ignored in full mode. |
| dateFilter | Values: today, tomorrow, weekend, dayOfWeek, custom | Eastern calendar days. weekend is Friday to Sunday of this week (the current weekend on a Saturday or Sunday). Omitted, all or unrecognized: every upcoming event. |
| dateStart | Values: YYYY-MM-DD | With dateFilter=custom: the first day. Without it, custom applies no date limit. |
| dateEnd | Values: YYYY-MM-DD | With dateFilter=custom: the last day, inclusive. Leave it off for a single day. |
| days | Values: Comma list of 0 to 6 (0 is Sunday) | With dateFilter=dayOfWeek: the days of the week to keep, in Eastern time. |
| times | Values: Comma list of morning, afternoon, evening | Eastern start time: morning 5:00 to 11:59 AM, afternoon noon to 4:59 PM, evening 5:00 PM to 2:59 AM. Events with no listed start time always pass. |
| priceFilter | Values: any, confirmedFree, free, under20, under100, custom | confirmedFree: events the source lists as free. free: those plus events with no listed price. See prices. |
| maxPrice | Values: Number, like 20 | With priceFilter=custom: the highest price to keep, inclusive. See prices. |
| tagsInclude | Values: Comma list of tags | Keep events that have at least one of these tags. Exact and case-sensitive. |
| tagsExclude | Values: Comma list of tags | Drop events that have any of these tags. |
| search | Values: Text; commas separate alternatives | Case-insensitive substring match on title, description, organizer and location; an event matching any one term is kept. Tags and AI summaries are not searched. In the Markdown export the whole value is one phrase. |
| locations | Values: Comma list: asheville, Online, or a town such as Black Mountain | asheville keeps Asheville and known Asheville venues. A town name must match the town AVL GO reads from the location text, capitalized as shown. |
| zips | Values: Comma list of ZIP codes | Keep events in these ZIP codes. Events with no ZIP code are dropped. |
| blockedHosts | Values: Comma list | Drop events whose organizer contains any of these (case-insensitive). |
| blockedKeywords | Values: Comma list | Drop events whose title contains any of these (case-insensitive). |
| hiddenEvents | Values: URL-encoded JSON array of {"title": "…", "organizer": "…"} | Drop specific events. Compared with the event’s lowercased, trimmed title and organizer, so send the values lowercased and trimmed. |
| useDefaultFilters | Values: false to turn off | On by default: a built-in keyword filter hides likely spam listings. |
| showDailyEvents | Values: false to turn off | On by default: include events that repeat every day. |
What else should I know?
Do I need an API key?
- No. There is no key, sign-up or authentication, and CORS is open (
Access-Control-Allow-Origin: *), so browser code can call the API directly. - Please be considerate: request compact pages with a small
limit, cache what you fetch, and avoid polling more often than every few minutes. The full export holds every upcoming event with long descriptions and can run to several megabytes, so fetch it occasionally rather than per user request.
How fresh is the data?
- Successful responses carry
Cache-Control: public, max-age=60, s-maxage=300, stale-while-revalidate=60: a browser can reuse a response for 60 seconds and a shared cache for 300, then serve it for up to 60 seconds more while it fetches a fresh copy. - Compact pages are also cached on the server for 300 seconds, or until the next scrape refreshes the events.
- Those caches stack, so check
generated(UTC) to see when the response you have was built. - Sources are collected on a schedule, most of them several times a day; a few are refreshed by periodic manual runs and can fall behind. Freshness and availability are best-effort.
Dates and time zone
- All dates and date filters use Eastern time (
America/New_York). - Compact
startDatecarries the UTC offset in effect at that moment:-04:00during daylight saving time,-05:00otherwise. - A date-only
startDatesuch as2026-10-04means the source gave no start time; don’t present it as midnight. Full mode always returns a UTC timestamp, so checktimeUnknownthere: when it istrue, only the date is meaningful. - Results start at midnight Eastern today; past days never appear. Events that repeat daily are included unless you send
showDailyEvents=false.
Paging
- Repeat the request with the same filters and
limit, addingcursorset to thenextCursoryou got back, URL-encoded. Treat the cursor as opaque and don’t build your own. - Stop when
hasMoreisfalse;nextCursorisnullexactly then. - A page can hold fewer events than
limit, even none, whilehasMoreis stilltrue: each request scans a fixed number of listings, and heavy filters can use them up before the page fills. Keep followingnextCursor. - Pages are ordered by
startDate, thenid.countis the number of events in the page; there is no total count. - Pages are not a snapshot. Listings can change between requests, so de-duplicate by
id.
Which URL should I link to?
- In compact mode,
urlis the event’s AVL GO page (https://www.avlgo.com/events/…), which shows the details and links to the original listing. In full mode,urlis the original listing itself, such as the venue’s page or the ticketing site.
Prices and the free filter
- In compact responses,
priceis the source’s own wording (for exampleFree,$15,$5 - $10,DonationorTicketed), ornullwhen none is listed, including the placeholderUnknown. The full and Markdown exports show the raw text. priceFilter=confirmedFreekeeps events the source lists as free: the price is exactlyFree(any case) or a single zero amount such as$0or$0.00. Donation-based and other wording is not included.priceFilter=freekeeps those plus events with no listed price (missing,UnknownorTBD; many of these are free), any price mentioning “free” or “donation” (Free with RSVP,$25 suggested donation), and prices whose first number is 0 ($0 - $20). Priced text with no number, such asTicketed, is not free.- For
under20,under100andcustom, each price is read as a number. Text containing “free” or “donation” counts as 0; otherwise the first number in the text is used ($5 - $10counts as 5,$1,200as 1200). A missing price or text with no number (Ticketed,Unknown) also counts as 0, so those events pass every threshold. under20andunder100keep prices counted at 20 or 100 or less.customkeeps those at or belowmaxPrice, read withparseFloat: send a plain number likemaxPrice=20, because$20or anything else that doesn’t start with a number applies no limit.
Errors
- 400 with
{"error":"Invalid format"},{"error":"Invalid limit"}or{"error":"Invalid cursor"}when that parameter is present but empty or malformed. - 500 with
{"error":"Failed to generate JSON feed"}. Errors are never cached (Cache-Control: no-store). - Other parameters are lenient: most unrecognized values are ignored (an unknown
dateFilterapplies no date limit), while an unknown tag or town, or an unreadable custom date (in either export), simply matches nothing. If results look wrong, check the spelling.
Using the data
- Please credit AVL GO and link to the event’s AVL GO page or to avlgo.com.
- Listings come from third-party sources, and summaries and tags are written by AI. Times, prices and cancellations can change or be wrong, so confirm with the organizer or the original listing before attending.
- Questions or problems: open an issue on GitHub.