Quickstart
Build an event feed end to end through the API: create it, add the websites its events come from, give it an area, decide what it carries, enable it and read its events.
Prerequisites
- A Helix API key (see Authentication)
- A command-line terminal or API client
Step 1: Create a Feed
curl -X POST https://api.feeds.onhelix.ai/feeds/events \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Community Events",
"description": "Local community happenings and activities"
}'
Response:
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Community Events",
"description": "Local community happenings and activities",
"organizationId": "660e8400-e29b-41d4-a716-446655440001",
"enabled": false,
"enabledSource": "system",
"enabledReason": null,
"config": {
"version": 1
},
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}
Save the id. The new feed starts disabled, with one filter, the
completeness opt-in, which leaves out events with too little detail. It has
no include filter yet, so you enable it in Step 5, after Step 4 adds one.
(Sending "enabled": true here is refused with 422 and creates nothing.)
Step 2: Add Websites
Add each website your events come from. The whole site is added, whatever the path. A disabled feed takes no events in: the site's events from the past 14 days reach the feed when you enable it in Step 5.
curl -X POST "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/sources" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "site",
"url": "https://www.blumenthalarts.org/events"
}'
Response:
{
"success": true,
"data": {
"id": "9b2f6c1e-4d3a-4e8b-9c7d-2a1b0f3e5d64",
"type": "site",
"identity": {
"domain": "www.blumenthalarts.org"
},
"enabled": true,
"addedAt": "2026-10-28T14:05:00.000Z"
}
}
Adding the same site twice (with or without www.) is a 409. Source adds
are limited to 30 per minute per organization, across your event and news
feeds: over it, the add is refused with 429 RATE_LIMITED and a
Retry-After header (seconds). Listing pages, sitemaps and social accounts
are added by our team: contact support. See
Sources.
Step 3: Create an Area
An area is two processors: an area match, which checks the event's venue against the area's boundaries, and an optional area relevance, which judges from the event's text whether it takes place there. Create the area match with your places:
curl -X POST "https://api.feeds.onhelix.ai/processors" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "area_match",
"name": "Charlotte metro",
"definition": {
"area": {
"name": "Charlotte metro",
"places": [
{ "name": "Mecklenburg County, North Carolina" },
{ "name": "Gaston County, North Carolina" },
{ "name": "Rock Hill, South Carolina", "level": "place" }
]
}
}
}'
Place names are resolved when you send them: a name without a level is a
county (district). The response returns each place resolved, with an id
you can send back later instead of the name. A name that is not exactly one
place is refused with 422 AREA_PLACES_UNRESOLVED, listing candidates.
Requests that look up places are limited to 30 per minute per organization
(429 RATE_LIMITED with Retry-After over it); a request that only sends
back places your areas already hold, by id, is not counted. See
Areas.
Then, to also catch events whose venue the map gets wrong, create the area relevance processor with the same places:
curl -X POST "https://api.feeds.onhelix.ai/processors" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template": "area_relevance",
"name": "Charlotte metro (relevance)",
"definition": {
"area": {
"name": "Charlotte metro",
"places": [
{ "name": "Mecklenburg County, North Carolina" },
{ "name": "Gaston County, North Carolina" },
{ "name": "Rock Hill, South Carolina", "level": "place" }
]
}
}
}'
Save both processors' ids.
Step 4: Decide What the Feed Carries
Add the Community events set of opt-in filters, passing your two area processors:
curl -X POST "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/filter-sets/community_events" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"with": {
"areaMatch": "5c0e8f9a-3b1d-4f6e-9a2c-7d4b1e0f8a63",
"areaRelevance": "0a7d2c4e-9f1b-4e3a-8c6d-1b2e3f4a5c6d"
}
}'
The set adds excludes for age-restricted, promotional and not-an-occasion events, and the "In the area" include. The feed already has the completeness filter, so that member is skipped:
{
"success": true,
"data": {
"added": [
{
"id": "7f3c2b1a-6e5d-4c4b-9a3f-2e1d0c9b8a71",
"name": "In the area",
"action": "include",
"type": "opt_in",
"optIn": {
"key": "in_area",
"with": {
"areaMatch": "5c0e8f9a-3b1d-4f6e-9a2c-7d4b1e0f8a63",
"areaRelevance": "0a7d2c4e-9f1b-4e3a-8c6d-1b2e3f4a5c6d"
}
},
"condition": {
"any": [
{
"processor": "5c0e8f9a-3b1d-4f6e-9a2c-7d4b1e0f8a63",
"output": "match",
"op": "=",
"value": "match"
},
{
"processor": "0a7d2c4e-9f1b-4e3a-8c6d-1b2e3f4a5c6d",
"output": "answer",
"op": "=",
"value": "yes"
}
]
},
"createdAt": "2026-10-28T14:05:00.000Z",
"updatedAt": "2026-10-28T14:05:00.000Z"
}
],
"skipped": [
{
"optIn": "completeness",
"equalTo": "3e9a1c7b-2d4f-4a8e-b6c5-9f0e1d2c3b4a"
}
]
}
}
(Shortened: added lists every filter the set added.) List the feed's
filters at any time with GET /feeds/events/{feedId}/filters.
Your own filters
You can add your own filters beside the opt-ins. An event is in the feed when no exclude matches and at least one include does, so your own include widens the feed. With "In the area" on the feed, this include also lets in family events from anywhere:
curl -X POST "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/filters" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Family events",
"action": "include",
"condition": {
"processor": "event_labels",
"output": "family_friendly.confidence",
"op": ">=",
"value": 0.8
}
}'
To narrow the feed instead, add an exclude:
curl -X POST "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/filters" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "No family-unfriendly events",
"action": "exclude",
"condition": {
"any": [
{
"processor": "event_labels",
"output": "age_restricted.confidence",
"op": ">=",
"value": 0.6
},
{
"processor": "event_category",
"output": "primary",
"op": "in",
"value": ["nightlife"]
}
]
}
}'
Filters apply going forward: to new events, and to events already in the feed when they next change.
Step 5: Enable the Feed
curl -X PATCH "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "enabled": true }'
Enabling needs at least one include filter: the set added one (without one,
the request is a 422). Enabling adds the events your sites brought in during
the past 14 days that pass the feed's filters, once per site.
Step 6: Retrieve Events
Once those events have been decided (a few minutes), fetch events from your feed:
curl "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/items?limit=10" \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"success": true,
"data": {
"items": [
{
"id": "3f6c1d52-7a0e-4b8e-9d1c-5a2b8e4f6a10",
"eventId": "9b2e7c44-1d3a-4f65-8a7b-0c5d2e9f1b33",
"addedToFeedAt": "2026-10-20T14:03:00.000Z",
"updatedAt": "2026-10-24T09:12:00.000Z",
"status": "active",
"title": "Toddler Story Time",
"description": "Stories, songs and rhymes for children ages 1 to 3 and their caregivers at the Main Library. Free, no registration needed.",
"shortDescription": "Stories and songs for ages 1 to 3.",
"completeness": {
"score": 0.85,
"missing": ["ticketUrl"]
},
"when": {
"pattern": "recurring",
"timezone": "America/New_York",
"displayText": "Alternating Wednesdays, 9:00 AM – 9:45 AM",
"recurrence": {
"description": "9-9:45 a.m. on alternating Wednesdays",
"startDate": "2026-03-04",
"endDate": "2026-12-31",
"exceptions": ["2026-07-08"],
"patterns": [
{
"rule": "FREQ=WEEKLY;INTERVAL=2;BYDAY=WE",
"startTime": "09:00",
"endTime": "09:45",
"description": "Alternating Wednesdays"
}
]
},
"next": {
"start": "2026-11-11T14:00:00.000Z",
"end": "2026-11-11T14:45:00.000Z",
"allDay": false,
"status": "scheduled"
},
"occurrences": [
{
"start": "2026-11-11T14:00:00.000Z",
"end": "2026-11-11T14:45:00.000Z",
"allDay": false,
"status": "scheduled"
},
{
"start": "2026-11-25T14:00:00.000Z",
"end": "2026-11-25T14:45:00.000Z",
"allDay": false,
"status": "scheduled"
},
{
"start": "2026-12-09T14:00:00.000Z",
"end": "2026-12-09T14:45:00.000Z",
"allDay": false,
"status": "scheduled"
},
{
"start": "2026-12-23T14:00:00.000Z",
"end": "2026-12-23T14:45:00.000Z",
"allDay": false,
"status": "scheduled"
}
],
"upcomingCount": 4
},
"where": {
"displayText": "Main Library, 310 North Tryon Street, Charlotte, NC 28202",
"venue": {
"name": "Main Library"
},
"address": {
"display": "310 North Tryon Street, Charlotte, North Carolina 28202, United States",
"street": "310 North Tryon Street",
"city": "Charlotte",
"region": "North Carolina",
"postcode": "28202",
"country": "United States",
"countryCode": "US"
},
"geo": {
"lat": 35.2271,
"lng": -80.8431,
"precision": "address"
}
},
"links": {
"best": {
"url": "https://www.cmlibrary.org/events/toddler-story-time",
"kind": "event_page",
"official": true,
"relation": "confirmed",
"publisher": {
"name": "Charlotte Mecklenburg Library",
"domain": "cmlibrary.org",
"platform": "web",
"role": "organizer",
"roleConfidence": "verified"
},
"publishedAt": "2026-10-01T12:00:00.000Z",
"reason": "official_event_page"
},
"all": [
{
"url": "https://www.cmlibrary.org/events/toddler-story-time",
"kind": "event_page",
"official": true,
"relation": "confirmed",
"publisher": {
"name": "Charlotte Mecklenburg Library",
"domain": "cmlibrary.org",
"platform": "web",
"role": "organizer",
"roleConfidence": "verified"
},
"publishedAt": "2026-10-01T12:00:00.000Z"
}
]
},
"media": {
"cover": {
"url": "https://example.r2.cloudflarestorage.com/media/2026-10/abc.jpg?X-Amz-Signature=...",
"expiresAt": "2026-10-28T12:00:00.000Z",
"usage": "cover_eligible",
"kind": "flyer",
"width": 1080,
"height": 1350,
"source": {
"imageUrl": "https://www.cmlibrary.org/sites/default/files/story-time.jpg",
"pageUrl": "https://www.cmlibrary.org/events/toddler-story-time",
"publisher": {
"name": "Charlotte Mecklenburg Library",
"domain": "cmlibrary.org",
"platform": "web",
"role": "organizer",
"roleConfidence": "verified"
}
}
},
"images": [
{
"url": "https://example.r2.cloudflarestorage.com/media/2026-10/abc.jpg?X-Amz-Signature=...",
"expiresAt": "2026-10-28T12:00:00.000Z",
"usage": "cover_eligible",
"kind": "flyer",
"width": 1080,
"height": 1350,
"source": {
"imageUrl": "https://www.cmlibrary.org/sites/default/files/story-time.jpg",
"pageUrl": "https://www.cmlibrary.org/events/toddler-story-time",
"publisher": {
"name": "Charlotte Mecklenburg Library",
"domain": "cmlibrary.org",
"platform": "web",
"role": "organizer",
"roleConfidence": "verified"
}
}
}
]
}
}
],
"total": 25,
"pagination": {
"limit": 10,
"offset": 0,
"hasMore": true
}
}
}
Each item says when the event happens (when), where (where), which pages to send people to (links, with a recommended links.best) and its images (media). See the API reference for every field, and Concepts for how to pick the more-info link.
Step 7: Disable or Re-enable Your Feed
You can pause and resume event monitoring for your feed. Re-enabling resumes monitoring; it does not add the events published while the feed was disabled (a site you added while it was disabled brings in its past 14 days):
# Disable feed temporarily
curl -X PATCH "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
# Re-enable feed
curl -X PATCH "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'
Next Steps
Now that you're retrieving events, you can:
- Set up event delivery: Register a destination and subscribe it to this feed to get notified when new events are added, instead of polling
- Filter by date range: Use
sinceanduntilparameters - Narrow the feed: Use
pattern,hasOfficialLink,hasCover,minCompleteness,addedSinceandupdatedSince - Paginate results: Use
limitandoffsetto retrieve large result sets - Monitor feed status: Check if your feed is enabled and processing
Common Patterns
Filter Events by Date Range
since and until must lie between 7 days in the past and 30 days in the
future: replace the dates below with a week inside that range.
# Get events for a specific week
curl "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/items?since=2026-11-02T00:00:00Z&until=2026-11-08T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_KEY"
Paginate Through Results
Offsets count items as they are at the time of each request. If an item leaves the feed while you page, the later items move up one place.
# Get first page
curl "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/items?limit=20&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"
# Get second page
curl "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000/items?limit=20&offset=20" \
-H "Authorization: Bearer YOUR_API_KEY"
Check Feed Status
# Get feed details
curl "https://api.feeds.onhelix.ai/feeds/events/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer YOUR_API_KEY"
Need Help?
Contact Helix support to add listing pages, sitemaps or social accounts to a feed, or for help choosing its processors and filters.
Learn More
- API Reference: Complete endpoint documentation
- Event Feed Concepts: Understanding the event data model
- Feed Configuration: Processors, filters, opt-in filters, areas and sources
- Workflows: Common integration patterns
- Event Delivery Concepts: How deliveries, destinations, and subscriptions work