# EventFinder Data API — `https://ef.bulkowski.org/data/v2/`

Live music and event listings, machine-readable. Data version 20261021-173303.

## Start here

**Agents that can only open links they have already seen** (chat assistants'
fetch tools): start at the browse index, `https://ef.bulkowski.org/city/san_francisco_metro/browse/`. It
links every day of the next 30, and each day links its event types and
regions, so any date × type × region slice is at most three links away. Each
page lists its events (time, title, venue, price, types, links) as plain HTML.

**Programs that build URLs**: use the files and the search API below.

## Record tiers

Every event is published in two tiers. **Full is mainline plus extras**, so a
mainline record is always a strict subset of the full one.

| Tier | Served by |
|---|---|
| **mainline** | `events/YYYY-MM-DD.json`, `today.json`, `next_7.json`, `bundle.json`, the browse pages, the search API by default |
| **full** | `events/YYYY-MM-DD.full.json`, `event/{event_id}.json` (one event), the search API with `tier=full` |

Every mainline record carries `full`, the absolute URL of its full record, so an
agent that can only follow links it has seen can open any event's details.

### Mainline fields

| Field | Type | Description |
|---|---|---|
| `event_id` | string | Persistent opaque identifier (`evt_<12 hex>`): assigned once when the event is first seen and kept across fetches, title and time corrections and moves. Never derived from the event's attributes. |
| `title` | string | Event title. |
| `start` | string | Start time, city-local ISO 8601 with no offset: `YYYY-MM-DDTHH:MM`, or `YYYY-MM-DD` when no time is known. |
| `venue_id` | string | Key into `venues.json`: the venue's `id` with a `venue_` prefix (strip the prefix to look it up). |
| `venue_name` | string | Venue display name. |
| `neighborhood` | string | The venue's neighborhood (from `venues.json`); `""` when unknown. |
| `regions` | list[str] | Every `geo.json` region whose list contains the neighborhood. A neighborhood can be in several: Oakland is in "Oakland" and "East Bay". |
| `price` | string | Price as the listing states it; `""` when not stated. |
| `description` | string | Text judged to describe this event, held to 500 characters; `""` when no text does. |
| `types` | list[str] | Event type ids from `event_types.json`. |
| `rating` | int | Ranking signal, a placeholder: the highest operator rating among the sources currently listing the event; 0 when none does. |
| `confirmed` | bool | `true` when the venue's own page, a feed, or two sources list the event. `false` means one model-found listing: check with the venue. |
| `listed` | bool | `false` once no source lists the event any more (it may be cancelled or moved). It stays, marked, for a retention window, then disappears. |
| `url` | string | The event's page, falling back to the page of a source that lists it. |
| `full` | string | Absolute URL of this event's full record (JSON only). |

### Full-only fields

| Field | Type | Description |
|---|---|---|
| `listed_by` | list[{name, url}] | The sources listing the event, each with the page it was found on. For an event no longer listed: the sources that last listed it. |
| `last_seen` | string | When a source last showed the event: ISO 8601 UTC with `Z`. |
| `run` | object or null | For one performance of a run (a theatrical run, a residency): `{label, start, end, open, schedule, n_dates}`. `end` is `""` and `open` is `true` while no closing date is posted. `null` for a one-off. |

## Endpoints (sizes measured on this build)

| You want | URL | Tier | Size |
|---|---|---|---|
| Linked pages by date × type × region | `https://ef.bulkowski.org/city/{city}/browse/` | mainline | HTML |
| Today | `https://ef.bulkowski.org/data/v2/cities/{city}/events/today.json` | mainline | 122.5 KB |
| Today + 6 days | `https://ef.bulkowski.org/data/v2/cities/{city}/events/next_7.json` | mainline | 937.0 KB |
| One date | `https://ef.bulkowski.org/data/v2/cities/{city}/events/YYYY-MM-DD.json` | mainline | median 13.7 KB, max 199.0 KB |
| One date, full records | `https://ef.bulkowski.org/data/v2/cities/{city}/events/YYYY-MM-DD.full.json` | full | median 17.5 KB |
| One event | `https://ef.bulkowski.org/data/v2/cities/{city}/event/{event_id}.json` (or follow a record's `full` link) | full | ~1 KB |
| Filtered query | `https://ef.bulkowski.org/api/v2/events/search?...` | mainline (`tier=full` for full) | varies |
| Dates on offer + counts | `https://ef.bulkowski.org/data/v2/cities/{city}/events/index.json` | — | small |
| Whole city, all dates | `https://ef.bulkowski.org/data/v2/cities/{city}/bundle.json` | mainline | 5.4 MB — batch use |
| Venues / regions | `https://ef.bulkowski.org/data/v2/cities/{city}/venues.json`, `.../geo.json` | — | small |
| Every file with size + sha256 | `https://ef.bulkowski.org/data/v2/manifest.json` | — | small |
| Freshness probe | `https://ef.bulkowski.org/data/v2/version.json` | — | ~100 B |

City slugs and timezones: `https://ef.bulkowski.org/data/v2/cities.json`. A whole-city or
all-city bundle overflows most model context windows; it is for offline
indexing.

## Search

`GET https://ef.bulkowski.org/api/v2/events/search` filters server-side. All parameters are
optional: `city`, `event_type`, `region`, `neighborhood`, `venue`, `date_from`,
`date_to` (YYYY-MM-DD, default today + 7 days in the city's timezone), `q`
(free text over title, venue and description), `limit` (1-1000, default 200),
`tier` (`mainline`, the default, or `full`). The response echoes the filters
and carries `count`, `total_matches` and `truncated`.

## Filtering by region or neighborhood

Records carry `neighborhood` and `regions` directly: no join is needed. A
region's neighborhoods are listed in `geo.json`; a venue's details (address,
website) are in `venues.json` under `venue_id` without its `venue_` prefix.

## Timezone semantics

`start` is a **naive ISO string in the city's local timezone** (no `Z`, no
offset); the zone is in `cities.json` and `city_config.json` (e.g.
`America/Los_Angeles`). `last_seen` is UTC with a `Z`. `today.json` and
`next_7.json` resolve "today" in the city's timezone at request time.

## Cache validation

1. `https://ef.bulkowski.org/data/v2/version.json` returns `{version, generated_at, sha256}`;
   the `sha256` is the master `bundle.json`'s, and its HTTP `ETag`.
2. `ETag` + `If-None-Match` on static files returns `304 Not Modified` when
   your copy is current.
3. `https://ef.bulkowski.org/data/v2/manifest.json` lists every file with its sha256.

## Sample records

The first event of the latest date file, so this stays current with the data.

Mainline:

```json
{
  "event_id": "evt_0882e4c95cd6",
  "title": "Bomba Estéreo",
  "start": "2027-06-21",
  "venue_id": "venue_stern_grove",
  "venue_name": "Stern Grove",
  "neighborhood": "Outer Sunset",
  "regions": [
    "San Francisco"
  ],
  "price": "SOLD OUT | Lottery Closed",
  "description": "With La Misa Negra & KEXP DJ Albina Cabrera",
  "types": [
    "live_music",
    "latin_world",
    "dj_party"
  ],
  "rating": 8,
  "confirmed": true,
  "listed": true,
  "url": "https://www.sterngrove.org/bombaestereo",
  "full": "https://ef.bulkowski.org/data/v2/cities/san_francisco_metro/event/evt_0882e4c95cd6.json"
}
```

Full:

```json
{
  "event_id": "evt_0882e4c95cd6",
  "title": "Bomba Estéreo",
  "start": "2027-06-21",
  "venue_id": "venue_stern_grove",
  "venue_name": "Stern Grove",
  "neighborhood": "Outer Sunset",
  "regions": [
    "San Francisco"
  ],
  "price": "SOLD OUT | Lottery Closed",
  "description": "With La Misa Negra & KEXP DJ Albina Cabrera",
  "types": [
    "live_music",
    "latin_world",
    "dj_party"
  ],
  "rating": 8,
  "confirmed": true,
  "listed": true,
  "url": "https://www.sterngrove.org/bombaestereo",
  "full": "https://ef.bulkowski.org/data/v2/cities/san_francisco_metro/event/evt_0882e4c95cd6.json",
  "listed_by": [
    {
      "name": "Stern Grove",
      "url": "https://www.sterngrove.org/lineup{year}"
    }
  ],
  "last_seen": "2026-07-26T10:57:30Z",
  "run": null
}
```

## Discovery

- `https://ef.bulkowski.org/city/san_francisco_metro/browse/` — linked pages (start here when you can only follow links)
- `https://ef.bulkowski.org/llms.txt` — LLM-oriented index
- `https://ef.bulkowski.org/.well-known/agent-card.json` — A2A agent card
- `https://ef.bulkowski.org/robots.txt`, `https://ef.bulkowski.org/sitemap.xml`
- `X-Agent-Data: https://ef.bulkowski.org/data/v2/manifest.json` on every response, and an RFC 8288 `Link` header
