ivy/developers

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"
      }
    }
  ]
}

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. OPTIONS preflights get 204 with Access-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-After header in seconds. Wait that long, then retry.
  • Caching: JSON 200 responses send Cache-Control: public, s-maxage=60, stale-while-revalidate=300 and a weak ETag. Send it back as If-None-Match to get 304 Not Modified with an empty body. A 404 for one event is cached for 60 seconds. 400, 429 and 500 responses send no-store. Calendar feeds send public, 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 (query, string, optional, default next7)
    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.
    Values: all, past, today, next7, weekend, week, month
  • from (query, string (date-time), optional)
    Inclusive lower bound on the event start, ISO 8601. Overrides the preset's start.
    Example: 2030-05-03T00:00:00-04:00
  • to (query, string (date-time), optional)
    Exclusive upper bound on the event start, ISO 8601. Overrides the preset's end.
    Example: 2030-05-10T00:00:00-04:00
  • type (query, string, optional, default all)
    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.
    Values: all, party, live_music, art, reading_talks, tech, fitness_outdoor, food_drink, comedy_performance, film, markets_community, music, theater, reading, talk
  • category (query, string, optional)
    Exact match on the event's category, case-insensitive.
    Example: film
  • neighborhood (query, string, optional)
    Neighborhood or area, by name or slug, case-insensitive. Matches the event's neighborhood, area.name or area.slug.
    Example: williamsburg
  • q (query, string, optional)
    Case-insensitive substring of the title.
    Example: jazz
  • sort (query, string, optional, default date)
    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.
    Values: date, links, newest, trending
  • limit (query, integer, optional, default 50, min 1, max 200)
    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 (query, string, optional, pattern ^[A-Za-z0-9_-]+$)
    Opaque next_cursor from the previous page. Only valid with the sort it was issued for; anything else is a 400.
  • view (query, string, optional, default full)
    Response shape. `agent` returns a compact pre-formatted event list in America/New_York time. Omit or use `full` for the default response.
    Values: 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

  • 200 (application/json) One page of events.
    Headers: Cache-Control: public, s-maxage=60, stale-while-revalidate=300; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 304 Not Modified: If-None-Match matched the current ETag. Empty body.
    Headers: Cache-Control: public, s-maxage=60, stale-while-revalidate=300; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 400 (application/json) Invalid query parameter. error is one of: Invalid preset or date range, Invalid sort, Invalid limit, Invalid cursor.
    Body: { "error": "Invalid limit" }
    Headers: Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 429 (application/json) Too Many Requests: more than 60 requests per minute from this IP.
    Body: { "error": "Rate limit exceeded" }
    Headers: Retry-After: 42; Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 500 (application/json) Unexpected server error. Retry later.
    Body: { "error": "Internal error" }
    Headers: 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 (path, string (uuid), required)
    Event id (UUID).
    Example: 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

  • 200 (application/json) The event.
    Headers: Cache-Control: public, s-maxage=60, stale-while-revalidate=300; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 304 Not Modified: If-None-Match matched the current ETag. Empty body.
    Headers: Cache-Control: public, s-maxage=60, stale-while-revalidate=300; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 404 (application/json) No public event with this id.
    Body: { "error": "Not found" }
    Headers: Cache-Control: public, s-maxage=60; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 429 (application/json) Too Many Requests: more than 60 requests per minute from this IP.
    Body: { "error": "Rate limit exceeded" }
    Headers: Retry-After: 42; Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 500 (application/json) Unexpected server error. Retry later.
    Body: { "error": "Internal error" }
    Headers: 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

  • 200 (application/json) Summary.
    Headers: Cache-Control: public, s-maxage=300, stale-while-revalidate=600; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 304 Not Modified: If-None-Match matched the current ETag. Empty body.
    Headers: Cache-Control: public, s-maxage=60, stale-while-revalidate=300; ETag: W/"3q2bMv8m9hS2l0bA4yYk1n0xZ9c"; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 429 (application/json) Too Many Requests: more than 60 requests per minute from this IP.
    Body: { "error": "Rate limit exceeded" }
    Headers: Retry-After: 42; Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 500 (application/json) Unexpected server error. Retry later.
    Body: { "error": "Internal error" }
    Headers: 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 (query, string, optional)
    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.
    Example: williamsburg
  • type (query, string, optional, default all)
    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.
    Values: all, party, live_music, art, reading_talks, tech, fitness_outdoor, food_drink, comedy_performance, film, markets_community, music, theater, reading, talk
  • category (query, string, optional)
    Exact match on the event's category, case-insensitive.
    Example: film
  • trending (query, string, optional, default false)
    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.
    Values: true, false, 1, 0
  • limit (query, integer, optional, default 200, min 1, max 200)
    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

  • 200 (text/calendar) An 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.
    Headers: 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.
  • 400 (text/plain) Invalid query parameter. Plain text, one of: Invalid trending (use true or false), Invalid limit (1 to 200).
    Body: Invalid limit (1 to 200)
    Headers: Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 404 (text/plain) Unknown neighborhood (plain text "Unknown neighborhood"), or for /feed/{slug}.ics a path without the .ics suffix ("Not found").
    Body: Unknown neighborhood
    Headers: Cache-Control: public, s-maxage=60; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 429 (application/json) Too Many Requests: more than 60 requests per minute from this IP.
    Body: { "error": "Rate limit exceeded" }
    Headers: Retry-After: 42; Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 500 (text/plain) Unexpected server error (plain text "Internal error"). Retry later.
    Body: Internal error
    Headers: Cache-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 (path, string, required)
    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.
    Example: williamsburg
  • trending (query, string, optional, default false)
    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.
    Values: true, false, 1, 0
  • limit (query, integer, optional, default 200, min 1, max 200)
    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

  • 200 (text/calendar) An 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.
    Headers: 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.
  • 400 (text/plain) Invalid query parameter. Plain text, one of: Invalid trending (use true or false), Invalid limit (1 to 200).
    Body: Invalid limit (1 to 200)
    Headers: Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 404 (text/plain) Unknown neighborhood (plain text "Unknown neighborhood"), or for /feed/{slug}.ics a path without the .ics suffix ("Not found").
    Body: Unknown neighborhood
    Headers: Cache-Control: public, s-maxage=60; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 429 (application/json) Too Many Requests: more than 60 requests per minute from this IP.
    Body: { "error": "Rate limit exceeded" }
    Headers: Retry-After: 42; Cache-Control: no-store; Access-Control-Allow-Origin: Always *: any origin may call the API.
  • 500 (text/plain) Unexpected server error (plain text "Internal error"). Retry later.
    Body: Internal error
    Headers: Cache-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 (string)
    When the response was generated.
  • count (integer)
    Number of events in this page.
  • next_cursor (string or null)
    Pass as cursor to get the next page; null on the last page.

Event

  • id (string)
    Event id.
  • title (string)
    Event title.
  • date (string)
    Start time, ISO 8601.
  • end_date (string, optional)
    End time, ISO 8601. Omitted when the event has no end time.
  • image_url (string or null)
    Cover image URL.
  • category (string or null)
    Free-form category (mostly Ivy-native events).
  • event_types (array of string)
    Event type slugs, possibly empty.
    Values: party, live_music, art, reading_talks, tech, fitness_outdoor, food_drink, comedy_performance, film, markets_community
  • source (string or null)
    Where the event comes from: native (created on Ivy) or the source platform, e.g. luma, partiful, posh, eventbrite, dice.
  • external_url (string or null)
    The event's page on its source platform.
  • price_text (string or null)
    Price as shown by the source, e.g. Free or $20.
  • location (string or null)
    Location text.
  • visibility (string or null)
    Visibility level of the event on Ivy.
    Values: discoverable, ambient_only
  • venue_name (string or null)
    Venue name.
  • neighborhood (string)
    NYC neighborhood, or "No location yet" when unknown.
  • area (Area)
    The heatmap area the neighborhood belongs to.
  • area.slug (string)
  • area.name (string)
  • node_count (integer)
    Number of Ivy users who linked this event ("Link This").
  • link_count (integer)
    Alias of node_count (same value).
  • node_count_delta (integer, optional)
    Links gained in the last 24 hours: current links created within 24h of as_of. Omitted if link timestamps are unavailable.
  • link_count_delta (integer, optional)
    Alias of node_count_delta.
  • url (string)
    The event's page on Ivy: https://www.ivylink.co/e/{id}.
  • attribution (Attribution or null)
    Credit for aggregated events; null for events created on Ivy.
  • attribution.source (string)
  • attribution.source_url (string or null)
    HTTPS link to the event on its source, when available.
  • attribution.text (string)

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) or agent. The agent view 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 adds timezone, and limit defaults to 5.
  • source is native for events created on Ivy, or the platform the event came from. external_url is the event on that platform. attribution is the credit to show with it; it is null for native events.
  • url is the canonical Ivy page for the event: https://www.ivylink.co/e/<id>.
  • node_count_delta may 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.ics or /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 source and external_url, show attribution.text linked to attribution.source_url, and link the Ivy url.
  • Credit ivylink.co wherever you use the data.
  • Do not republish event images. Link to image_url or 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.