Ivy For Developers
A free, read-only API and calendar feeds for public events in New York City. Machine-readable versions: /llms.txt and the OpenAPI spec at /api/docs.
What Ivy Is
Ivy is a map of what is happening in New York City. It pulls events from Luma, Partiful, Posh, Eventbrite, DICE and more, plus events created on Ivy, into one free API. node_count is the number of Ivy users who linked an event; node_count_delta is links in the last 24 hours.
Quick Start
Three requests, no key. Illustrative sample: field shapes match the live API; the events in them are made up, and your results will show current events.
1. This Week's Events
Request
curl "https://www.ivylink.co/api/public/events?preset=week&limit=2"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"count": 2,
"next_cursor": "eyJ2IjoxLCJzIjoiZGF0ZSIsImsiOlsxOTA0MTYyNDAwMDAwLCIyMjIyMjIyMi0yMjIyLTQyMjItODIyMi0yMjIyMjIyMjIyMjIiXX0",
"events": [
{
"id": "11111111-1111-4111-8111-111111111111",
"title": "Example Reading Night",
"date": "2030-05-03T23:00:00+00:00",
"end_date": "2030-05-04T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/reading-night.jpg",
"category": null,
"event_types": [
"reading_talks"
],
"source": "luma",
"external_url": "https://luma.com/example-reading-night",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Bookshop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 3,
"link_count": 3,
"node_count_delta": 1,
"link_count_delta": 1,
"url": "https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-reading-night",
"text": "Via Luma"
}
},
{
"id": "22222222-2222-4222-8222-222222222222",
"title": "Example Gallery Opening",
"date": "2030-05-04T22:00:00+00:00",
"end_date": "2030-05-05T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/gallery-opening.jpg",
"category": null,
"event_types": [
"art"
],
"source": "partiful",
"external_url": "https://partiful.com/e/example-gallery-opening",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Gallery",
"neighborhood": "SoHo-Little Italy-Hudson Square",
"area": {
"slug": "soho-tribeca",
"name": "SoHo / Tribeca"
},
"node_count": 2,
"link_count": 2,
"node_count_delta": 0,
"link_count_delta": 0,
"url": "https://www.ivylink.co/e/22222222-2222-4222-8222-222222222222",
"attribution": {
"source": "partiful",
"source_url": "https://partiful.com/e/example-gallery-opening",
"text": "Via Partiful"
}
}
]
}2. Trending in a Neighborhood
Request
curl "https://www.ivylink.co/api/public/events?sort=trending&neighborhood=williamsburg&limit=2"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"count": 2,
"next_cursor": null,
"events": [
{
"id": "11111111-1111-4111-8111-111111111111",
"title": "Example Reading Night",
"date": "2030-05-03T23:00:00+00:00",
"end_date": "2030-05-04T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/reading-night.jpg",
"category": null,
"event_types": [
"reading_talks"
],
"source": "luma",
"external_url": "https://luma.com/example-reading-night",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Bookshop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 3,
"link_count": 3,
"node_count_delta": 1,
"link_count_delta": 1,
"url": "https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-reading-night",
"text": "Via Luma"
}
},
{
"id": "33333333-3333-4333-8333-333333333333",
"title": "Example Rooftop Set",
"date": "2030-05-05T00:00:00+00:00",
"end_date": "2030-05-05T03:00:00+00:00",
"image_url": "https://www.ivylink.co/example/rooftop-set.jpg",
"category": null,
"event_types": [
"live_music"
],
"source": "luma",
"external_url": "https://luma.com/example-rooftop-set",
"price_text": "$15",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Rooftop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 1,
"link_count": 1,
"node_count_delta": 0,
"link_count_delta": 0,
"url": "https://www.ivylink.co/e/33333333-3333-4333-8333-333333333333",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-rooftop-set",
"text": "Via Luma"
}
}
]
}3. One Event
Request
curl "https://www.ivylink.co/api/public/events/11111111-1111-4111-8111-111111111111"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"event": {
"id": "11111111-1111-4111-8111-111111111111",
"title": "Example Reading Night",
"date": "2030-05-03T23:00:00+00:00",
"end_date": "2030-05-04T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/reading-night.jpg",
"category": null,
"event_types": [
"reading_talks"
],
"source": "luma",
"external_url": "https://luma.com/example-reading-night",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Bookshop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 3,
"link_count": 3,
"node_count_delta": 1,
"link_count_delta": 1,
"url": "https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-reading-night",
"text": "Via Luma"
}
}
}Authentication and Limits
- No authentication. No key, no sign-up, no headers required.
- CORS is open: every response sends
Access-Control-Allow-Origin: *, so you can call the API from a browser.OPTIONSpreflights get 204 withAccess-Control-Allow-Methods: GET, OPTIONS. - Rate limit: 60 requests per minute per IP, shared by the JSON API and the calendar feeds. Over the limit you get 429 with a
Retry-Afterheader in seconds. Wait that long, then retry. - Caching: JSON 200 responses send
Cache-Control: public, s-maxage=60, stale-while-revalidate=300and a weakETag. Send it back asIf-None-Matchto get 304 Not Modified with an empty body. A 404 for one event is cached for 60 seconds. 400, 429 and 500 responses sendno-store. Calendar feeds sendpublic, s-maxage=900, stale-while-revalidate=3600(15 minutes). - Be polite: cache on your side, reuse the ETag, page with the cursor instead of hammering, and do not poll the same URL more than once a minute. Data changes slowly.
Rate limited
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Cache-Control: no-store
Access-Control-Allow-Origin: *
{"error":"Rate limit exceeded"}Conditional request
curl -i "https://www.ivylink.co/api/public/events?preset=week"
# ETag: W/"..."
curl -i -H 'If-None-Match: W/"..."' "https://www.ivylink.co/api/public/events?preset=week"
# HTTP/1.1 304 Not Modified (empty body)Endpoint Reference
Generated from the OpenAPI spec at /api/docs. Base URL https://www.ivylink.co. All endpoints are GET.
Pagination With Cursor
List responses are { as_of, count, next_cursor, events }. When next_cursor is not null, repeat the same request with cursor=<next_cursor> (same sort) for the next page. Stop when it is null. A cursor from a different sort is a 400.
Request (page two of the first Quick Start call)
curl "https://www.ivylink.co/api/public/events?preset=week&limit=2&cursor=eyJ2IjoxLCJzIjoiZGF0ZSIsImsiOlsxOTA0MTYyNDAwMDAwLCIyMjIyMjIyMi0yMjIyLTQyMjItODIyMi0yMjIyMjIyMjIyMjIiXX0"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"count": 2,
"next_cursor": null,
"events": [
{
"id": "33333333-3333-4333-8333-333333333333",
"title": "Example Rooftop Set",
"date": "2030-05-05T00:00:00+00:00",
"end_date": "2030-05-05T03:00:00+00:00",
"image_url": "https://www.ivylink.co/example/rooftop-set.jpg",
"category": null,
"event_types": [
"live_music"
],
"source": "luma",
"external_url": "https://luma.com/example-rooftop-set",
"price_text": "$15",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Rooftop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 1,
"link_count": 1,
"node_count_delta": 0,
"link_count_delta": 0,
"url": "https://www.ivylink.co/e/33333333-3333-4333-8333-333333333333",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-rooftop-set",
"text": "Via Luma"
}
},
{
"id": "44444444-4444-4444-8444-444444444444",
"title": "Example Comedy Hour",
"date": "2030-05-05T01:30:00+00:00",
"image_url": "https://www.ivylink.co/example/comedy-hour.jpg",
"category": null,
"event_types": [
"comedy_performance"
],
"source": "partiful",
"external_url": "https://partiful.com/e/example-comedy-hour",
"price_text": "$10",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Club",
"neighborhood": "East Village",
"area": {
"slug": "east-village",
"name": "East Village"
},
"node_count": 0,
"link_count": 0,
"node_count_delta": 0,
"link_count_delta": 0,
"url": "https://www.ivylink.co/e/44444444-4444-4444-8444-444444444444",
"attribution": {
"source": "partiful",
"source_url": "https://partiful.com/e/example-comedy-hour",
"text": "Via Partiful"
}
}
]
}Errors
JSON endpoints return { "error": "..." }. Calendar feed errors are plain text.
Bad request (illustrative sample)
curl "https://www.ivylink.co/api/public/events?limit=0"
# 400
{
"error": "Invalid limit"
}Not found (illustrative sample)
curl "https://www.ivylink.co/api/public/events/00000000-0000-0000-0000-000000000000"
# 404
{
"error": "Not found"
}GET /api/public/events
List public events. Public, active events in a date window (default: the next 7 days, America/New_York). Filters combine with AND. Results are paged with an opaque cursor: pass next_cursor from one page as cursor (with the same sort) to get the next page; next_cursor is null on the last page.
Also answers OPTIONS (CORS preflight): 204 with no body.
Parameters
preset
Named date window in America/New_York. today runs until 04:00 the next morning. all has no date bounds (Ivy-native events of any date plus aggregated events from today through the next 60 days). from / to override the matching bound.all,past,today,next7,weekend,week,monthfrom
Inclusive lower bound on the event start, ISO 8601. Overrides the preset's start.2030-05-03T00:00:00-04:00to
Exclusive upper bound on the event start, ISO 8601. Overrides the preset's end.2030-05-10T00:00:00-04:00type
Event type slug (matches if any of the event's event_types matches). all means no filter. Legacy values music, theater, reading and talk are mapped onto live_music, comedy_performance and reading_talks; any other value is accepted but matches nothing.all,party,live_music,art,reading_talks,tech,fitness_outdoor,food_drink,comedy_performance,film,markets_community,music,theater,reading,talkcategory
Exact match on the event's category, case-insensitive.filmneighborhood
Neighborhood or area, by name or slug, case-insensitive. Matches the event's neighborhood, area.name or area.slug.williamsburgq
Case-insensitive substring of the title.jazzsort
date: start time ascending. links: node_count descending, then start time. newest: most recently added to Ivy first. trending: node_count_delta descending, then node_count descending, then start time. Falls back to links order if link timestamps are unavailable.date,links,newest,trendinglimit
Page size. A positive integer; values above 200 are clamped to 200. 0, negatives and non-integers are a 400. Defaults to 5 with view=agent.cursor
Opaque next_cursor from the previous page. Only valid with the sort it was issued for; anything else is a 400.view
Response shape. `agent` returns a compact pre-formatted event list in America/New_York time. Omit or use `full` for the default response.full,agent
Example
Request
curl "https://www.ivylink.co/api/public/events?preset=week&limit=2"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"count": 2,
"next_cursor": "eyJ2IjoxLCJzIjoiZGF0ZSIsImsiOlsxOTA0MTYyNDAwMDAwLCIyMjIyMjIyMi0yMjIyLTQyMjItODIyMi0yMjIyMjIyMjIyMjIiXX0",
"events": [
{
"id": "11111111-1111-4111-8111-111111111111",
"title": "Example Reading Night",
"date": "2030-05-03T23:00:00+00:00",
"end_date": "2030-05-04T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/reading-night.jpg",
"category": null,
"event_types": [
"reading_talks"
],
"source": "luma",
"external_url": "https://luma.com/example-reading-night",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Bookshop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 3,
"link_count": 3,
"node_count_delta": 1,
"link_count_delta": 1,
"url": "https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-reading-night",
"text": "Via Luma"
}
},
{
"id": "22222222-2222-4222-8222-222222222222",
"title": "Example Gallery Opening",
"date": "2030-05-04T22:00:00+00:00",
"end_date": "2030-05-05T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/gallery-opening.jpg",
"category": null,
"event_types": [
"art"
],
"source": "partiful",
"external_url": "https://partiful.com/e/example-gallery-opening",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Gallery",
"neighborhood": "SoHo-Little Italy-Hudson Square",
"area": {
"slug": "soho-tribeca",
"name": "SoHo / Tribeca"
},
"node_count": 2,
"link_count": 2,
"node_count_delta": 0,
"link_count_delta": 0,
"url": "https://www.ivylink.co/e/22222222-2222-4222-8222-222222222222",
"attribution": {
"source": "partiful",
"source_url": "https://partiful.com/e/example-gallery-opening",
"text": "Via Partiful"
}
}
]
}Responses
200One page of events.Cache-Control: public, s-maxage=60, stale-while-revalidate=300;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.304Not Modified: If-None-Match matched the current ETag. Empty body.Cache-Control: public, s-maxage=60, stale-while-revalidate=300;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.400Invalid query parameter. error is one of: Invalid preset or date range, Invalid sort, Invalid limit, Invalid cursor.{ "error": "Invalid limit" }Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.429Too Many Requests: more than 60 requests per minute from this IP.{ "error": "Rate limit exceeded" }Retry-After: 42;Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.500Unexpected server error. Retry later.{ "error": "Internal error" }Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.
GET /api/public/events/{id}
Get one public event. One event with the same fields as the list items. Unknown ids, malformed ids and events that are not public all return the same 404.
Also answers OPTIONS (CORS preflight): 204 with no body.
Parameters
id
Event id (UUID).e7c8fc2f-16d3-4e43-80ca-988a945024bc
Example
Request
curl "https://www.ivylink.co/api/public/events/11111111-1111-4111-8111-111111111111"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"event": {
"id": "11111111-1111-4111-8111-111111111111",
"title": "Example Reading Night",
"date": "2030-05-03T23:00:00+00:00",
"end_date": "2030-05-04T01:00:00+00:00",
"image_url": "https://www.ivylink.co/example/reading-night.jpg",
"category": null,
"event_types": [
"reading_talks"
],
"source": "luma",
"external_url": "https://luma.com/example-reading-night",
"price_text": "Free",
"location": null,
"visibility": "discoverable",
"venue_name": "Example Bookshop",
"neighborhood": "Williamsburg",
"area": {
"slug": "williamsburg",
"name": "Williamsburg"
},
"node_count": 3,
"link_count": 3,
"node_count_delta": 1,
"link_count_delta": 1,
"url": "https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111",
"attribution": {
"source": "luma",
"source_url": "https://luma.com/example-reading-night",
"text": "Via Luma"
}
}
}Responses
200The event.Cache-Control: public, s-maxage=60, stale-while-revalidate=300;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.304Not Modified: If-None-Match matched the current ETag. Empty body.Cache-Control: public, s-maxage=60, stale-while-revalidate=300;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.404No public event with this id.{ "error": "Not found" }Cache-Control: public, s-maxage=60;Access-Control-Allow-Origin: Always *: any origin may call the API.429Too Many Requests: more than 60 requests per minute from this IP.{ "error": "Rate limit exceeded" }Retry-After: 42;Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.500Unexpected server error. Retry later.{ "error": "Internal error" }Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.
GET /api/public/summary
Live counts and starter questions for the next 7 days. Returns event counts for the next 7 New York days (total, tonight, this weekend, by day, by type, busiest neighborhoods) and four suggested questions built from those counts. No params. Call it once at the start of a conversation, before fetching any events. Covers the same events as /api/public/events for preset=next7.
Also answers OPTIONS (CORS preflight): 204 with no body.
Parameters
None.
Example
Request
curl "https://www.ivylink.co/api/public/summary"Response (illustrative sample)
{
"as_of": "2030-05-03T16:00:00.000Z",
"window": {
"from": "2030-05-03",
"to": "2030-05-09"
},
"event_count": 4,
"neighborhood_count": 3,
"tonight_count": 1,
"weekend_count": 4,
"busiest_neighborhoods": [
{
"slug": "williamsburg",
"name": "Williamsburg",
"count": 2
},
{
"slug": "east-village",
"name": "East Village",
"count": 1
},
{
"slug": "soho-tribeca",
"name": "SoHo / Tribeca",
"count": 1
}
],
"by_day": [
{
"date": "2030-05-03",
"weekday": "Friday",
"count": 1
},
{
"date": "2030-05-04",
"weekday": "Saturday",
"count": 3
},
{
"date": "2030-05-05",
"weekday": "Sunday",
"count": 0
},
{
"date": "2030-05-06",
"weekday": "Monday",
"count": 0
},
{
"date": "2030-05-07",
"weekday": "Tuesday",
"count": 0
},
{
"date": "2030-05-08",
"weekday": "Wednesday",
"count": 0
},
{
"date": "2030-05-09",
"weekday": "Thursday",
"count": 0
}
],
"by_type": [
{
"type": "art",
"count": 1
},
{
"type": "comedy_performance",
"count": 1
},
{
"type": "live_music",
"count": 1
},
{
"type": "reading_talks",
"count": 1
}
],
"suggested_questions": [
"What's on in Williamsburg tonight?",
"What's happening this weekend?",
"Any art shows this week?",
"What's on in Williamsburg on Saturday night?"
]
}Responses
200Summary.Cache-Control: public, s-maxage=300, stale-while-revalidate=600;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.304Not Modified: If-None-Match matched the current ETag. Empty body.Cache-Control: public, s-maxage=60, stale-while-revalidate=300;ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c";Access-Control-Allow-Origin: Always *: any origin may call the API.429Too Many Requests: more than 60 requests per minute from this IP.{ "error": "Rate limit exceeded" }Retry-After: 42;Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.500Unexpected server error. Retry later.{ "error": "Internal error" }Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.
GET /api/feed
iCalendar feed of upcoming events. The next 30 days of public events (from now, max 200) as an RFC 5545 calendar. Subscribe with the https URL or the same URL with webcal://. Filters combine with AND. No auth; 60 requests per minute per IP, shared with the JSON API.
Also answers OPTIONS (CORS preflight): 204 with no body.
Parameters
neighborhood
A known NYC neighborhood or area, by name or slug, case-insensitive (Ivy's curated areas, their legacy names, and NYC 2020 Neighborhood Tabulation Area names). Matches the event's neighborhood, area.name or area.slug. An unknown neighborhood is a 404; a known one with no events returns an empty calendar.williamsburgtype
Event type slug (matches if any of the event's event_types matches). all means no filter. Legacy values music, theater, reading and talk are mapped onto live_music, comedy_performance and reading_talks; any other value is accepted but matches nothing.all,party,live_music,art,reading_talks,tech,fitness_outdoor,food_drink,comedy_performance,film,markets_community,music,theater,reading,talkcategory
Exact match on the event's category, case-insensitive.filmtrending
true (or 1) orders by node_count_delta (links in the last 24 hours) descending, then node_count descending, then start time, the same order as sort=trending on /api/public/events (links order if link timestamps are unavailable). Calendar apps display by date anyway, so this mostly matters with a small limit. false (or 0) or absent: start time ascending.true,false,1,0limit
Maximum number of events. A positive integer; values above 200 are clamped to 200. 0, negatives and non-integers are a 400.
Example
Request
curl "https://www.ivylink.co/api/feed?type=music&limit=2"Response (illustrative sample, first event only)
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Ivy//ivylink.co//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Ivy: Live music
X-WR-CALDESC:Live music events on Ivy (ivylink.co)\, the next 30 days. Upda
ted hourly.
X-WR-TIMEZONE:America/New_York
REFRESH-INTERVAL;VALUE=DURATION:PT1H
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:33333333-3333-4333-8333-333333333333@ivylink.co
DTSTAMP:20300503T160000Z
DTSTART:20300505T000000Z
DTEND:20300505T030000Z
SUMMARY:Example Rooftop Set
DESCRIPTION:1 link on Ivy\nPrice: $15\nOn Ivy: https://www.ivylink.co/e/333
33333-3333-4333-8333-333333333333\nVia Luma: https://luma.com/example-roof
top-set
URL:https://www.ivylink.co/e/33333333-3333-4333-8333-333333333333
LOCATION:Example Rooftop
CATEGORIES:Live music
STATUS:CONFIRMED
TRANSP:TRANSPARENT
END:VEVENT
Responses
200An iCalendar (RFC 5545) feed: one VCALENDAR (VERSION 2.0, PRODID -//Ivy//ivylink.co//EN, X-WR-CALNAME "Ivy: <filter>", X-WR-TIMEZONE America/New_York, REFRESH-INTERVAL and X-PUBLISHED-TTL of 1 hour) with one VEVENT per event: UID <id>@ivylink.co, DTSTAMP (response time), DTSTART and DTEND in UTC (DTEND is DTSTART + 2 hours when the event has no end time), SUMMARY, DESCRIPTION (link counts, price, the Ivy URL and the source credit and link), URL (the Ivy event page), LOCATION, CATEGORIES (event types), STATUS:CONFIRMED and TRANSP:TRANSPARENT. CRLF line endings, lines folded at 75 octets, UTF-8. No images and no user data. A known neighborhood with no events in the window returns an empty calendar.Cache-Control: public, s-maxage=900, stale-while-revalidate=3600;Content-Disposition: inline; filename="ivy-williamsburg.ics";Access-Control-Allow-Origin: Always *: any origin may call the API.400Invalid query parameter. Plain text, one of: Invalid trending (use true or false), Invalid limit (1 to 200).Invalid limit (1 to 200)Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.404Unknown neighborhood (plain text "Unknown neighborhood"), or for /feed/{slug}.ics a path without the .ics suffix ("Not found").Unknown neighborhoodCache-Control: public, s-maxage=60;Access-Control-Allow-Origin: Always *: any origin may call the API.429Too Many Requests: more than 60 requests per minute from this IP.{ "error": "Rate limit exceeded" }Retry-After: 42;Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.500Unexpected server error (plain text "Internal error"). Retry later.Internal errorCache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.
GET /feed/{slug}.ics
Subscribable calendar feed by neighborhood. Vanity URLs for GET /api/feed: /feed/all.ics, /feed/trending.ics and /feed/<neighborhood>.ics (same as /api/feed?neighborhood=<neighborhood>). Same calendar, headers and errors. Subscribe with webcal://www.ivylink.co/feed/williamsburg.ics.
Also answers OPTIONS (CORS preflight): 204 with no body.
Parameters
slug
all (every NYC event), trending (all NYC in trending order) or a known neighborhood or area slug such as williamsburg or east-village. The URL must end in .ics.williamsburgtrending
true (or 1) orders by node_count_delta (links in the last 24 hours) descending, then node_count descending, then start time, the same order as sort=trending on /api/public/events (links order if link timestamps are unavailable). Calendar apps display by date anyway, so this mostly matters with a small limit. false (or 0) or absent: start time ascending.true,false,1,0limit
Maximum number of events. A positive integer; values above 200 are clamped to 200. 0, negatives and non-integers are a 400.
Example
Request
curl "https://www.ivylink.co/feed/williamsburg.ics"Response (illustrative sample, first event only)
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Ivy//ivylink.co//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Ivy: Williamsburg
X-WR-CALDESC:Williamsburg events on Ivy (ivylink.co)\, the next 30 days. Up
dated hourly.
X-WR-TIMEZONE:America/New_York
REFRESH-INTERVAL;VALUE=DURATION:PT1H
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:11111111-1111-4111-8111-111111111111@ivylink.co
DTSTAMP:20300503T160000Z
DTSTART:20300503T230000Z
DTEND:20300504T010000Z
SUMMARY:Example Reading Night
DESCRIPTION:3 links on Ivy (1 in the last 24h)\nPrice: Free\nOn Ivy: https:
//www.ivylink.co/e/11111111-1111-4111-8111-111111111111\nVia Luma: https:/
/luma.com/example-reading-night
URL:https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111
LOCATION:Example Bookshop
CATEGORIES:Reading / talks
STATUS:CONFIRMED
TRANSP:TRANSPARENT
END:VEVENT
Responses
200An iCalendar (RFC 5545) feed: one VCALENDAR (VERSION 2.0, PRODID -//Ivy//ivylink.co//EN, X-WR-CALNAME "Ivy: <filter>", X-WR-TIMEZONE America/New_York, REFRESH-INTERVAL and X-PUBLISHED-TTL of 1 hour) with one VEVENT per event: UID <id>@ivylink.co, DTSTAMP (response time), DTSTART and DTEND in UTC (DTEND is DTSTART + 2 hours when the event has no end time), SUMMARY, DESCRIPTION (link counts, price, the Ivy URL and the source credit and link), URL (the Ivy event page), LOCATION, CATEGORIES (event types), STATUS:CONFIRMED and TRANSP:TRANSPARENT. CRLF line endings, lines folded at 75 octets, UTF-8. No images and no user data. A known neighborhood with no events in the window returns an empty calendar.Cache-Control: public, s-maxage=900, stale-while-revalidate=3600;Content-Disposition: inline; filename="ivy-williamsburg.ics";Access-Control-Allow-Origin: Always *: any origin may call the API.400Invalid query parameter. Plain text, one of: Invalid trending (use true or false), Invalid limit (1 to 200).Invalid limit (1 to 200)Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.404Unknown neighborhood (plain text "Unknown neighborhood"), or for /feed/{slug}.ics a path without the .ics suffix ("Not found").Unknown neighborhoodCache-Control: public, s-maxage=60;Access-Control-Allow-Origin: Always *: any origin may call the API.429Too Many Requests: more than 60 requests per minute from this IP.{ "error": "Rate limit exceeded" }Retry-After: 42;Cache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.500Unexpected server error (plain text "Internal error"). Retry later.Internal errorCache-Control: no-store;Access-Control-Allow-Origin: Always *: any origin may call the API.
Field Guide
A public event. Only event data: no data about Ivy users is ever included. The fields below are generated from the spec.
List Envelope
GET /api/public/events returns these plus events. GET /api/public/events/{id} returns as_of and event.
as_of
When the response was generated.count
Number of events in this page.next_cursor
Pass as cursor to get the next page; null on the last page.
Event
id
Event id.title
Event title.date
Start time, ISO 8601.end_date
End time, ISO 8601. Omitted when the event has no end time.image_url
Cover image URL.category
Free-form category (mostly Ivy-native events).event_types
Event type slugs, possibly empty.party,live_music,art,reading_talks,tech,fitness_outdoor,food_drink,comedy_performance,film,markets_communitysource
Where the event comes from: native (created on Ivy) or the source platform, e.g. luma, partiful, posh, eventbrite, dice.external_url
The event's page on its source platform.price_text
Price as shown by the source, e.g. Free or $20.location
Location text.visibility
Visibility level of the event on Ivy.discoverable,ambient_onlyvenue_name
Venue name.neighborhood
NYC neighborhood, or "No location yet" when unknown.area
The heatmap area the neighborhood belongs to.area.slugarea.namenode_count
Number of Ivy users who linked this event ("Link This").link_count
Alias of node_count (same value).node_count_delta
Links gained in the last 24 hours: current links created within 24h of as_of. Omitted if link timestamps are unavailable.link_count_delta
Alias of node_count_delta.url
The event's page on Ivy: https://www.ivylink.co/e/{id}.attribution
Credit for aggregated events; null for events created on Ivy.attribution.sourceattribution.source_url
HTTPS link to the event on its source, when available.attribution.text
Notes
- Dates are ISO 8601 with an offset (the API returns UTC,
+00:00). Date presets and day boundaries are computed in America/New_York; convert to that time zone for display. view:full(default) oragent. Theagentview returns a compact pre-formatted response in New York time (no UTC conversion needed): each event is{ title, when, ends, venue, neighborhood, price, url, via, via_url }, the envelope addstimezone, andlimitdefaults to 5.sourceisnativefor events created on Ivy, or the platform the event came from.external_urlis the event on that platform.attributionis the credit to show with it; it is null for native events.urlis the canonical Ivy page for the event:https://www.ivylink.co/e/<id>.node_count_deltamay be missing if link timestamps are unavailable. Treat a missing value as unknown, not 0.- Excluded: hidden, pending and removed events, events that are not active, and private (host only) events. No user data is ever included: no names, handles, emails or who linked what.
Calendar Feeds
Every feed is a live iCalendar (RFC 5545) file, text/calendar, with the next 30 days of public events (max 200). Times are in UTC and the calendar sets X-WR-TIMEZONE:America/New_York. No key, no images, no user data.
Feed URLs
- All of NYC:
https://www.ivylink.co/feed/all.ics - Trending (all of NYC, ordered by links in the last 24 hours):
https://www.ivylink.co/feed/trending.ics - One neighborhood:
https://www.ivylink.co/feed/<neighborhood-slug>.ics, for example/feed/williamsburg.icsor/feed/east-village.ics - One event type:
https://www.ivylink.co/api/feed?type=live_music(see the type values in the Endpoint Reference) - One category:
https://www.ivylink.co/api/feed?category=film - Combined:
https://www.ivylink.co/api/feed?neighborhood=williamsburg&type=party&trending=true&limit=20
An unknown neighborhood is a 404. A known neighborhood with no upcoming events is an empty calendar.
How To Subscribe
Use the https URL, or swap https:// for webcal:// to open it straight in your calendar app: webcal://www.ivylink.co/feed/williamsburg.ics
- Apple Calendar: File > New Calendar Subscription, paste the URL. You can set how often it refreshes.
- Google Calendar: next to Other calendars, choose + > From URL, paste the https URL.
- Outlook: Add calendar > Subscribe from web, paste the URL.
Refresh Behavior
Feeds ask clients to refresh hourly (REFRESH-INTERVAL and X-PUBLISHED-TTL of one hour) and the server caches each feed for 15 minutes, but calendar apps poll on their own schedule. Google Calendar can take 12 to 24 hours to pick up changes; Apple Calendar lets you choose.
curl "https://www.ivylink.co/feed/williamsburg.ics" (illustrative sample, first event only)
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Ivy//ivylink.co//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Ivy: Williamsburg
X-WR-CALDESC:Williamsburg events on Ivy (ivylink.co)\, the next 30 days. Up
dated hourly.
X-WR-TIMEZONE:America/New_York
REFRESH-INTERVAL;VALUE=DURATION:PT1H
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:11111111-1111-4111-8111-111111111111@ivylink.co
DTSTAMP:20300503T160000Z
DTSTART:20300503T230000Z
DTEND:20300504T010000Z
SUMMARY:Example Reading Night
DESCRIPTION:3 links on Ivy (1 in the last 24h)\nPrice: Free\nOn Ivy: https:
//www.ivylink.co/e/11111111-1111-4111-8111-111111111111\nVia Luma: https:/
/luma.com/example-reading-night
URL:https://www.ivylink.co/e/11111111-1111-4111-8111-111111111111
LOCATION:Example Bookshop
CATEGORIES:Reading / talks
STATUS:CONFIRMED
TRANSP:TRANSPARENT
END:VEVENT
Using Ivy With An Agent
No code and no API key. Works in any agent that can open a link: ChatGPT, Claude, Cursor, Claude Code, Hermes and others.
1. Try It Now
Paste this into any assistant that can open links.
Prompt
Read https://www.ivylink.co/llms.txt. Tell me what I can ask you.It reads /llms.txt, checks the live counts at /api/public/summary, and replies in a few short lines: how many events are on this week, where it is busiest, and a handful of questions to start with. The questions come from the counts, so the reply changes from day to day. No account or key needed.
Typical questions look like these:
- “What's on in the East Village tonight?”
- “What's happening this weekend?”
- “Any readings or art shows this week?”
- “What's on in Williamsburg on Saturday night?”
Pick one and ask.
2. Make It Stick (Optional)
To skip step 1 in every new chat, paste this into your agent's custom instructions once. After that, just ask about Ivy.
Custom instructions
When I mention Ivy, I mean ivylink.co, a map of NYC events. Answer by fetching
https://www.ivylink.co/api/public/events?limit=5&view=agent plus these query params (no API key needed):
- neighborhood: slug, e.g. east-village, williamsburg, lower-east-side
- preset: today, weekend, next7, month (or from/to as YYYY-MM-DD for specific dates)
- limit: up to 200 (default to 5 unless asked for more)
How to answer: show 5 events by default. Use view=agent. Show title, when, venue or neighborhood, the Ivy url and the via credit. If venue is null say the location is not listed yet. No UTC conversion needed: the when field is already in New York time. At most one clarifying question when needed. Never say nothing is on without checking the neighborhood slug is valid.
Ivy cannot link events for you (that needs a signed-in account on ivylink.co), buy tickets, RSVP, or filter by price.
For Williamsburg: query williamsburg AND east-williamsburg separately and merge the results. "LES" means lower-east-side.
If asked for trending or most linked: answer but note link counts are still small because Ivy is new.
Full docs: https://www.ivylink.co/llms.txt
When the user first asks what you can do with Ivy, call GET https://www.ivylink.co/api/public/summary first and use its suggested_questions as your starter bullets. Do not copy a fixed script.- ChatGPT: Settings > Personalization > Custom instructions
- Claude: Settings > Profile > personal preferences, or a Project’s instructions
- Claude Code: ~/.claude/CLAUDE.md
- Cursor: Settings > Rules > User rules
- Any other agent: its system prompt or custom instructions
For Agent Builders
Put this in your agent's system prompt or tool description:
Prompt
You can look up public events in New York City with Ivy (ivylink.co).
Read https://www.ivylink.co/llms.txt first, then use the OpenAPI spec at https://www.ivylink.co/api/docs.
No API key is needed. Stay under 60 requests per minute; on a 429, wait the
Retry-After seconds before retrying. Page with next_cursor until it is null.
When you show an event, give its title, date (America/New_York), venue, the
Ivy url, and credit the source with attribution.text linked to
attribution.source_url. node_count is the number of Ivy users who linked it.curl
# Search: titles containing "jazz" this week
curl "https://www.ivylink.co/api/public/events?preset=week&q=jazz&limit=5"
# Trending in Williamsburg
curl "https://www.ivylink.co/api/public/events?sort=trending&neighborhood=williamsburg&limit=10"
# Next page: pass next_cursor from the previous response as cursor
curl "https://www.ivylink.co/api/public/events?preset=week&limit=200&cursor=<next_cursor>"JavaScript (fetch)
const BASE = 'https://www.ivylink.co/api/public/events'
// Search: titles containing "jazz" this week
const search = await fetch(`${BASE}?preset=week&q=jazz&limit=5`).then(r => r.json())
// Trending in Williamsburg
const trending = await fetch(`${BASE}?sort=trending&neighborhood=williamsburg&limit=10`)
.then(r => r.json())
// Every event this week, page by page
async function allEvents(query) {
const events = []
let cursor = null
for (;;) {
const url = `${BASE}?${query}&limit=200${cursor ? `&cursor=${cursor}` : ''}`
const res = await fetch(url)
if (res.status === 429) {
const wait = Number(res.headers.get('Retry-After') || 60)
await new Promise(resolve => setTimeout(resolve, wait * 1000))
continue
}
if (!res.ok) throw new Error(`Ivy API ${res.status}`)
const page = await res.json()
events.push(...page.events)
cursor = page.next_cursor
if (cursor === null) return events
}
}
const week = await allEvents('preset=week')Python (requests)
import time
import requests
BASE = "https://www.ivylink.co/api/public/events"
# Search: titles containing "jazz" this week
search = requests.get(BASE, params={"preset": "week", "q": "jazz"}).json()
# Trending in Williamsburg
trending = requests.get(
BASE, params={"sort": "trending", "neighborhood": "williamsburg", "limit": 10}
).json()
# Every event this week, page by page
def all_events(params):
events, cursor = [], None
while True:
query = {**params, "limit": 200}
if cursor:
query["cursor"] = cursor
res = requests.get(BASE, params=query)
if res.status_code == 429:
time.sleep(int(res.headers.get("Retry-After", 60)))
continue
res.raise_for_status()
page = res.json()
events.extend(page["events"])
cursor = page["next_cursor"]
if cursor is None:
return events
week = all_events({"preset": "week"})Attribution and Terms of Use
- Most events come from third parties and link back to them. When you show an event, keep its
sourceandexternal_url, showattribution.textlinked toattribution.source_url, and link the Ivyurl. - Credit ivylink.co wherever you use the data.
- Do not republish event images. Link to
image_urlor the event page; do not copy, host or resize the image yourself. - Stay within 60 requests per minute per IP. Clients that ignore 429s or scrape around the limit may be blocked.
- Need higher limits, found a problem, or want to tell us what you built? Email hello@ivylink.co.
Changelog
- Added /api/public/summary: live event counts and suggested questions. First replies now built from live data.
- Sample responses on this page and in the spec are now illustrative, so they never show past events.
- One-line agent setup: paste the prompt and your agent lists what it can do with Ivy (/llms.txt now opens with that list).
- Four starter questions, casual reply, neighborhood and type guidance in /llms.txt.
- Public events API: GET /api/public/events and GET /api/public/events/{id} (F1a).
- OpenAPI 3.1 spec at /api/docs and agent guides at /llms.txt and /llms-full.txt (F1b).
- node_count_delta (links in the last 24 hours) and sort=trending (F2).
- Calendar feeds: /api/feed and /feed/{slug}.ics (F3).
- This page, /developers.
Coming Later
- MCP Server: Not available yet.