# NYC Events API

The Josh Burke NYC Events API is a public, anonymous, read-only interface to the calendar at [joshburke.xyz/events](https://joshburke.xyz/events). It is designed for agents helping someone find something to do tonight or soon.

All relative periods and displayed timestamps use `America/New_York`. Responses say exactly which dates and times the server interpreted.

The canonical date filter is an inclusive `start_date` / `end_date` range on each event's **local start date**. Late-night shows do not spill into the next day just because `ends_at` crosses midnight. `date` is the one-day shorthand, while `tonight`, `tomorrow`, `week`, and `weekend` are convenience macros that resolve to the same range.

## Fastest call

```http
GET https://joshburke-events-api.nebula-monitor.workers.dev/api/v1/events
```

With no parameters, the dynamic API returns up to 100 of tonight's higher-quality upcoming events. “Tonight” starts at 5pm; after 5pm, already-finished events are excluded. When the request truly had no filters, `interpreted_as.used_defaults` is `true` so callers can detect query-string stripping.

If a client cannot send query strings, use a path-based day feed:

```http
GET https://joshburke-events-api.nebula-monitor.workers.dev/api/v1/day/2026-08-29
GET https://joshburke.xyz/api/v1/day/2026-08-29.json
```

Static fallbacks are also generated whenever the calendar scrapes:

- `https://joshburke.xyz/api/v1/tonight.json`
- `https://joshburke.xyz/api/v1/tomorrow.json`
- `https://joshburke.xyz/api/v1/weekend.json`
- `https://joshburke.xyz/api/v1/day/{yyyy-MM-dd}.json` for today and the next 13 days

Static and dynamic search feeds both return up to 100 events. `truncated` is `true` when `total` exceeds `returned`.

## Search events

```http
GET https://joshburke-events-api.nebula-monitor.workers.dev/api/v1/events?period=tonight&after=19:00&borough=brooklyn,manhattan&category=music,weird&max_price=25
```

Specific day:

```http
GET https://joshburke-events-api.nebula-monitor.workers.dev/api/v1/events?date=2026-08-29
```

Inclusive date range:

```http
GET https://joshburke-events-api.nebula-monitor.workers.dev/api/v1/events?start_date=2026-08-29&end_date=2026-08-31
```

Parameters:

| Parameter | Values | Notes |
| --- | --- | --- |
| `period` | `tonight`, `tomorrow`, `week`, `weekend`, `custom` | Defaults to `tonight`; presets resolve to an inclusive date range. |
| `date` | `yyyy-MM-dd` | Single-day shortcut for `start_date=date&end_date=date`. |
| `start_date` / `end_date` | `yyyy-MM-dd` | Inclusive range on local **start** date; `end_date` defaults to `start_date`; maximum 31 days. Explicit dates automatically select custom mode. |
| `after` / `before` | `HH:mm` | Local start-time bounds. |
| `borough` | `manhattan`, `brooklyn`, `queens`, `bronx`, `staten-island`, `other` | Comma-separated or repeated; `boroughs` is accepted as an alias. |
| `category` | `music`, `theater`, `comedy`, `art`, `film`, `dance`, `community`, `action`, `singles`, `literary`, `market`, `party`, `workshop`, `weird`, `other` | Comma-separated or repeated; `categories` is accepted as an alias. |
| `source` | `calred`, `nycnoise`, `skint`, `nonsense`, `luma`, `comedybureau`, `artforum`, `ohmyrockness`, `brooklynvegan` | Comma-separated or repeated; `sources` is accepted as an alias. |
| `free_only` | `true` or `false` | Unknown prices do not count as free. |
| `max_price` | non-negative number | Events without a known minimum price are excluded. |
| `query` | up to 100 characters | Searches event data only. Keep personal context out of this field. |
| `limit` | `1`–`100` | Defaults to `100`. |

Unknown parameters and invalid enum values return `400` with a machine-readable error that lists the valid set. `GET /api/v1/vocabularies` (Worker) and `https://joshburke.xyz/api/v1/vocabularies.json` return those enums with how many matching tonight events currently use each value.

Search results include compact summaries; `GET /api/v1/events/{id}` returns full public details.

## MCP

The Streamable HTTP endpoint is:

```text
https://joshburke-events-api.nebula-monitor.workers.dev/mcp
```

It exposes:

- `find_events`: the structured equivalent of the search endpoint; calling it with `{}` means tonight. It accepts `date` for one day or `start_date` / `end_date` for a range without requiring `period: "custom"`.
- `get_event`: retrieves full details for an ID returned by `find_events`.

Both tools are anonymous and carry read-only, non-destructive annotations. No tool writes calendar or feedback data.

## Freshness, provenance, and limits

Every response includes the snapshot's `generated_at` time and source health. Each event includes source links and a stable ID. Search results are capped at 100 records and rate-limited to protect availability. A `429` response includes `Retry-After`.

`GET /api/v1/status` also exposes a privacy-preserving sampled estimate of the current UTC day's request volume and whether it has crossed the 50,000-request warning threshold. No IP addresses or agent identifiers are stored in the counter.

Each source includes `expected_cadence_hours`, `hours_since_success`, and `stale`. Daily scrapers are stale after 24 hours; Artforum is treated as weekly (168 hours). `source_alerts` lists the stale ones.

The private Firestore feedback collection is not part of this API or MCP server.
