Skip to main content

API Reference

Complete API reference for Helix News Feeds. All endpoints use JSON for request and response bodies.

Interactive playground

An interactive OpenAPI playground is available at api.feeds.onhelix.ai/docs. The spec is generated from the live route validators, so it cannot drift from the running implementation — useful for testing requests, inspecting response shapes, and generating client SDKs.

Base URL

https://api.feeds.onhelix.ai

Authentication

All requests require an API key in the Authorization header:

Authorization: Bearer YOUR_API_KEY

See the Authentication Guide for details.

News Feed Management

Create a Feed

Creates a new news feed to organize articles from multiple sources.

POST /feeds/news

Request

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Body:

{
"name": "Technology News",
"description": "Latest technology and startup news"
}

Parameters:

NameTypeRequiredDescription
namestringYesFeed name. Minimum 1 character.
descriptionstringYesFeed description. Minimum 1 character.

Response

Status: 201 Created

{
"success": true,
"data": {
"id": "feed_2aKj39dkD",
"name": "Technology News",
"description": "Latest technology and startup news",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}

Response object:

FieldTypeDescription
idstringUnique feed identifier. Use this when adding sources or retrieving items.
namestringFeed name
descriptionstringFeed description
createdAtstring (ISO 8601)When the feed was created
updatedAtstring (ISO 8601)Last time the feed was modified

Example

curl -X POST https://api.feeds.onhelix.ai/feeds/news \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Technology News",
"description": "Latest technology and startup news"
}'

List Feeds

Retrieves all news feeds.

GET /feeds/news

Request

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true,
"data": [
{
"id": "feed_2aKj39dkD",
"name": "Technology News",
"description": "Latest technology and startup news",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
},
{
"id": "feed_9xLm47qwP",
"name": "Business News",
"description": "Business and finance updates",
"createdAt": "2024-01-14T15:20:00.000Z",
"updatedAt": "2024-01-14T15:20:00.000Z"
}
]
}

Returns an array of feed objects sorted by creation date (newest first).

Example

curl https://api.feeds.onhelix.ai/feeds/news \
-H "Authorization: Bearer YOUR_API_KEY"

Get a Feed

Retrieves details for a specific feed.

GET /feeds/news/{feedId}

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier returned when creating the feed

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true,
"data": {
"id": "feed_2aKj39dkD",
"name": "Technology News",
"description": "Latest technology and startup news",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z"
}
}

Example

curl https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD \
-H "Authorization: Bearer YOUR_API_KEY"

Errors

  • 404: Feed not found

Update a Feed

Updates a feed's name, description, or enabled status.

PATCH /feeds/news/{feedId}

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Body (all fields optional):

{
"name": "Tech & Startup News",
"description": "Updated description",
"enabled": true
}

Parameters:

NameTypeRequiredDescription
namestringNoUpdated feed name
descriptionstringNoUpdated feed description
enabledbooleanNoEnable or disable the feed. When disabled, all sources stop monitoring.

Response

Status: 200 OK

{
"success": true,
"data": {
"id": "feed_2aKj39dkD",
"name": "Tech & Startup News",
"description": "Updated description",
"createdAt": "2024-01-15T10:30:00.000Z",
"updatedAt": "2024-01-15T14:25:00.000Z"
}
}

The updatedAt field reflects the modification time.

Example

curl -X PATCH https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Tech & Startup News",
"enabled": true
}'

Delete a Feed

Permanently deletes a feed and all its sources. This does not delete the underlying articles, only the feed configuration.

DELETE /feeds/news/{feedId}

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true
}

Warning: This action is permanent and cannot be undone.

Example

curl -X DELETE https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD \
-H "Authorization: Bearer YOUR_API_KEY"

Get Feed Items

Retrieves articles from a feed in a normalized, source-agnostic response shape that is consistent across all five content types (site, instagram, tiktok, twitter, facebook). This is the canonical endpoint for new integrations.

GET /feeds/news/{feedId}/items

A legacy endpoint at /v0/feeds/news/{feedId}/items returns the previous, more verbose response shape (per-content-type data envelope, internal IDs visible, nulls emitted). See Get Feed Items (v0, legacy) below.

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Query parameters:

NameTypeDefaultDescription
limitinteger50Number of items to return. Range: 1-100.
offsetinteger0Number of items to skip. Use for pagination.
sincestring (ISO 8601)-Only items created after this date. Example: 2024-01-15T00:00:00Z
untilstring (ISO 8601)-Only items created before this date. Example: 2024-01-20T23:59:59Z
includestring-Comma-separated list of optional response sections to include. Currently supported: source. Unknown tokens return 400.

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

The root of each item is source-agnostic — the same fields regardless of where the article came from. Optional fields are omitted (not nulled) when the underlying value is missing.

FieldTypeRequiredDescription
idstringyesStable feed-item identifier. Use this for client-side dedup, the singular item endpoint, and the feedback endpoint.
newsPageIdstringyesStable identifier of the underlying news article. The same value across all feeds containing this article — use it to correlate items across feeds.
titlestringnoHeadline / title of the original content (omitted when not available).
descriptionstringnoArticle body / caption / tweet text — content varies by source (omitted when empty).
urlstringnoCanonical link back to the original content.
imageUrlstringnoBest representative image (article hero, post media, or video thumbnail).
publishedAtstring (ISO 8601)noOriginal publish time on the source platform. Omitted when unknown.
createdAtstring (ISO 8601)yesWhen the item entered the feed.
updatedAtstring (ISO 8601)yesLast update.
sourceobjectnoPer-platform detail block, present only when the request used ?include=source. See Source block below. Carries the publisher (who posted the item) for social subtypes.

Note: there is no root-level author field. Publisher information ("who posted this") lives inside the source block and is returned only when the request opts in via ?include=source.

Strip-null semantics: any optional scalar field whose underlying value is null, undefined, or empty-after-trim is omitted from the response. Consumers should check for key presence ('title' in item) rather than for null.

?include=source block

When the request includes ?include=source, each item gains a source object whose shape is determined by source.type. The block carries content the consumer would otherwise need a second API call (or a separate platform integration) to obtain. Internal database identifiers are not exposed — consumers identify items by the root id and reach the original via permalinkUrl / url.

source.type: "site"

FieldTypeDescription
typestringAlways "site".
urlstringCanonical URL to the page.

Publisher object (carried by each of the four social source blocks below as publisher):

FieldTypeDescription
namestringDisplay name. Always present. Falls back to username for IG/TikTok/Twitter when the platform stores no distinct display name.
usernamestringRaw handle (no @ prefix). Omitted only when the platform does not expose one (rare on Facebook pages).
avatarUrlstringProfile picture URL (omitted when not available).
typestringFacebook only — page, group, or profile. Omitted for Instagram, TikTok, and Twitter.

source.type: "instagram"

FieldTypeDescription
typestringAlways "instagram".
subtypestringpost or reel.
permalinkUrlstringPublic Instagram URL.
captionstringPost caption (omitted when empty).
mediaUrlstringImage or video URL (omitted when empty).
thumbnailUrlstringThumbnail URL (omitted when empty).
publisherobjectSee Publisher object above.

source.type: "tiktok"

FieldTypeDescription
typestringAlways "tiktok".
subtypestringvideo.
permalinkUrlstringPublic TikTok URL.
captionstringVideo caption (omitted when empty).
mediaUrlstringVideo URL (omitted when empty).
thumbnailUrlstringThumbnail URL (omitted when empty).
publisherobjectSee Publisher object above.

source.type: "twitter"

FieldTypeDescription
typestringAlways "twitter".
subtypestringtweet, retweet, quote, or reply.
permalinkUrlstringPublic Twitter URL.
textstringTweet text (omitted when empty).
mediaUrlstringAttached media URL (omitted when empty).
publisherobjectSee Publisher object above.

source.type: "facebook"

FieldTypeDescription
typestringAlways "facebook".
subtypestringpost, video, photo, link, or event.
permalinkUrlstringPublic Facebook URL (omitted when not available).
textstringPost text / caption (omitted when empty).
mediaUrlstringAttached media URL (omitted when empty).
publisherobjectSee Publisher object above. Includes type (page/group/profile).

Platform-specific identifiers (Instagram code, TikTok tiktokId, Twitter tweetId, Facebook facebookId) are intentionally not exposed — permalinkUrl is the only way consumers reach the original content. If you need the platform-specific id, parse it from the URL.

Pagination object:

FieldTypeDescription
limitintegerItems per page (as requested)
offsetintegerCurrent offset (as requested)
hasMorebooleanWhether more items are available. If true, increment offset by limit to get the next page.

Examples

Default response (site article, no include):

{
"id": "item_3bNm58fwQ",
"title": "AI Startup Raises $100M Series B",
"description": "The company plans to expand its enterprise AI platform...",
"url": "https://techcrunch.com/2024/01/15/ai-startup-funding",
"imageUrl": "https://cdn.example.com/article-hero.jpg",
"publishedAt": "2024-01-15T11:30:00.000Z",
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}

Default response (Instagram post):

{
"id": "item_ig_001",
"description": "Breaking: new office opens downtown",
"url": "https://www.instagram.com/p/C123abcXYZ/",
"imageUrl": "https://cdn.example.com/ig/image.jpg",
"publishedAt": "2024-01-15T11:00:00.000Z",
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}

To resolve the publisher (account that posted the item), include the source block via ?include=source.

With ?include=source (Instagram post):

{
"id": "item_ig_001",
"description": "Breaking: new office opens downtown",
"url": "https://www.instagram.com/p/C123abcXYZ/",
"imageUrl": "https://cdn.example.com/ig/image.jpg",
"publishedAt": "2024-01-15T11:00:00.000Z",
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z",
"source": {
"type": "instagram",
"subtype": "post",
"permalinkUrl": "https://www.instagram.com/p/C123abcXYZ/",
"caption": "Breaking: new office opens downtown",
"mediaUrl": "https://cdn.example.com/ig/image.jpg",
"publisher": {
"name": "WCNC Charlotte",
"username": "wcnctv",
"avatarUrl": "https://cdn.example.com/ig/avatar.jpg"
}
}
}

With ?include=source (Facebook post):

{
"id": "item_fb_001",
"description": "Snow emergency declared — plows deployed across the metro.",
"url": "https://www.facebook.com/citynewspage/posts/123456789012345",
"publishedAt": "2024-01-15T07:00:00.000Z",
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z",
"source": {
"type": "facebook",
"subtype": "post",
"permalinkUrl": "https://www.facebook.com/citynewspage/posts/123456789012345",
"text": "Snow emergency declared — plows deployed across the metro.",
"publisher": {
"type": "page",
"name": "City News Page",
"username": "citynewspage",
"avatarUrl": "https://cdn.example.com/fb/avatar.jpg"
}
}
}

curl:

# Default shape
curl "https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items?limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"

# With per-platform source block
curl "https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items?limit=20&include=source" \
-H "Authorization: Bearer YOUR_API_KEY"

What changed from v0

v0 (/v0/feeds/news/...)Current (/feeds/news/...)
Root shapePer-content-type — { type, data: {...} } envelope.Source-agnostic — same keys for every content type.
type discriminatorAt the root.Moved to source.type (only present with ?include=source).
Null fieldsEmitted as null.Omitted from response.
Internal database idsExposed (sitePageId, instagramContentId, account.id, etc.).Hidden — consumers use the root id and the permalinkUrl / url.
?includenot supported.Supported. Currently allows source.

The envelope ({ items, total, pagination }) is identical between versions.


Get Feed Items (v0, legacy)

Returns articles in the original verbose response shape: per-content-type data envelope, internal IDs visible, nulls preserved. Kept for backwards compatibility — new integrations should use Get Feed Items above.

GET /v0/feeds/news/{feedId}/items

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Query parameters:

NameTypeDefaultDescription
limitinteger50Number of items to return. Range: 1-100.
offsetinteger0Number of items to skip. Use for pagination.
sincestring (ISO 8601)-Only items created after this date. Example: 2024-01-15T00:00:00Z
untilstring (ISO 8601)-Only items created before this date. Example: 2024-01-20T23:59:59Z

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true,
"data": {
"items": [
{
"id": "item_3bNm58fwQ",
"newsPageId": "page_7xQr92jkL",
"type": "site",
"data": {
"sitePageId": "550e8400-e29b-41d4-a716-446655440003",
"sitePageVersionId": "550e8400-e29b-41d4-a716-446655440004",
"url": "https://techcrunch.com/2024/01/15/ai-startup-funding",
"title": "AI Startup Raises $100M Series B",
"description": "The company plans to expand its enterprise AI platform..."
},
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
],
"total": 156,
"pagination": {
"limit": 50,
"offset": 0,
"hasMore": true
}
}
}

Feed item object:

FieldTypeDescription
idstringUnique item identifier
newsPageIdstringInternal reference to the news page
typestringContent type: site, instagram, tiktok, twitter, or facebook
dataobjectItem data. Shape depends on type — see per-type schemas below.
createdAtstring (ISO 8601)When the item was added to the feed
updatedAtstring (ISO 8601)Last update time

data shape by type:

type: "site" — articles crawled from websites (also includes items sourced from sitemap and index-page configurations):

FieldTypeDescription
data.sitePageIdstringInternal site page identifier
data.sitePageVersionIdstringVersion of the page this item refers to
data.urlstringArticle URL
data.titlestring|nullArticle headline
data.descriptionstring|nullArticle summary

type: "instagram":

FieldTypeDescription
data.instagramContentIdstringInternal Instagram content id
data.codestringInstagram shortcode
data.typestringpost or reel
data.permalinkUrlstringPublic Instagram URL
data.captionstring|nullPost caption
data.mediaUrlstring|nullImage or video URL
data.thumbnailUrlstring|nullThumbnail URL (for videos/reels)
data.publishedAtstring (ISO 8601)When originally posted
data.account.idstringAccount id
data.account.usernamestring@username
data.account.fullNamestring|nullDisplay name
data.account.profilePicUrlstring|nullAvatar URL

type: "tiktok":

FieldTypeDescription
data.tiktokContentIdstringInternal TikTok content id
data.tiktokIdstringTikTok's video id
data.typestringvideo
data.permalinkUrlstringPublic TikTok URL
data.captionstring|nullVideo caption
data.mediaUrlstring|nullVideo URL
data.thumbnailUrlstring|nullThumbnail URL
data.publishedAtstring (ISO 8601)When originally posted
data.account.idstringAccount id
data.account.usernamestring@username
data.account.displayNamestring|nullDisplay name
data.account.profilePicUrlstring|nullAvatar URL

type: "twitter":

FieldTypeDescription
data.twitterContentIdstringInternal Twitter content id
data.tweetIdstringTwitter's tweet id
data.typestringtweet, retweet, quote, or reply
data.permalinkUrlstringPublic Twitter URL
data.textstring|nullTweet text
data.mediaUrlstring|nullAttached media URL
data.publishedAtstring (ISO 8601)When originally posted
data.account.idstringAccount id
data.account.usernamestring@username
data.account.displayNamestring|nullDisplay name
data.account.profileImageUrlstring|nullAvatar URL

type: "facebook":

FieldTypeDescription
data.facebookContentIdstringInternal Facebook content id
data.facebookIdstringFacebook's internal content id
data.typestringpost, video, photo, link, or event
data.permalinkUrlstring|nullPublic Facebook URL (may be unavailable for some post types)
data.textstring|nullPost text / caption
data.mediaUrlstring|nullAttached media URL
data.publishedAtstring (ISO 8601)When originally posted
data.source.idstringFacebook source id (page/group/profile)
data.source.namestringSource display name
data.source.usernamestring|nullSource handle if available

Example responses by type:

{
"id": "item_ig_001",
"newsPageId": "page_ig_001",
"type": "instagram",
"data": {
"instagramContentId": "ig_content_001",
"code": "C123abcXYZ",
"type": "post",
"permalinkUrl": "https://www.instagram.com/p/C123abcXYZ/",
"caption": "Breaking: new office opens downtown",
"mediaUrl": "https://cdn.example.com/ig/image.jpg",
"thumbnailUrl": null,
"publishedAt": "2024-01-15T11:00:00.000Z",
"account": {
"id": "acc_ig_001",
"username": "wcnctv",
"fullName": "WCNC Charlotte",
"profilePicUrl": "https://cdn.example.com/ig/avatar.jpg"
}
},
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
{
"id": "item_tt_001",
"newsPageId": "page_tt_001",
"type": "tiktok",
"data": {
"tiktokContentId": "tt_content_001",
"tiktokId": "7312345678901234567",
"type": "video",
"permalinkUrl": "https://www.tiktok.com/@newsdaily/video/7312345678901234567",
"caption": "Major traffic delays downtown this morning",
"mediaUrl": "https://cdn.example.com/tt/video.mp4",
"thumbnailUrl": "https://cdn.example.com/tt/thumb.jpg",
"publishedAt": "2024-01-15T09:30:00.000Z",
"account": {
"id": "acc_tt_001",
"username": "newsdaily",
"displayName": "News Daily",
"profilePicUrl": "https://cdn.example.com/tt/avatar.jpg"
}
},
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
{
"id": "item_tw_001",
"newsPageId": "page_tw_001",
"type": "twitter",
"data": {
"twitterContentId": "tw_content_001",
"tweetId": "1745678901234567890",
"type": "tweet",
"permalinkUrl": "https://twitter.com/localreporter/status/1745678901234567890",
"text": "City council approves new transit plan — vote was 7-2.",
"mediaUrl": null,
"publishedAt": "2024-01-15T08:15:00.000Z",
"account": {
"id": "acc_tw_001",
"username": "localreporter",
"displayName": "Local Reporter",
"profileImageUrl": "https://cdn.example.com/tw/avatar.jpg"
}
},
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
{
"id": "item_fb_001",
"newsPageId": "page_fb_001",
"type": "facebook",
"data": {
"facebookContentId": "fb_content_001",
"facebookId": "123456789012345",
"type": "post",
"permalinkUrl": "https://www.facebook.com/citynewspage/posts/123456789012345",
"text": "Snow emergency declared — plows deployed across the metro.",
"mediaUrl": null,
"publishedAt": "2024-01-15T07:00:00.000Z",
"source": {
"id": "fb_src_001",
"name": "City News Page",
"username": "citynewspage"
}
},
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}

Pagination object:

FieldTypeDescription
limitintegerItems per page (as requested)
offsetintegerCurrent offset (as requested)
hasMorebooleanWhether more items are available. If true, increment offset by limit to get the next page.

Examples

Basic request:

curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"

Date filtering:

# Get articles from last 24 hours
YESTERDAY=$(date -u -d '1 day ago' +%Y-%m-%dT%H:%M:%SZ)
curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?since=$YESTERDAY" \
-H "Authorization: Bearer YOUR_API_KEY"

Pagination:

# Page 1
curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?limit=20&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"

# Page 2
curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?limit=20&offset=20" \
-H "Authorization: Bearer YOUR_API_KEY"

# Page 3
curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?limit=20&offset=40" \
-H "Authorization: Bearer YOUR_API_KEY"

Date range:

curl "https://api.feeds.onhelix.ai/v0/feeds/news/feed_2aKj39dkD/items?since=2024-01-15T00:00:00Z&until=2024-01-20T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_KEY"

Get a Single Feed Item

Returns a single item from a news feed by its itemId. The response wraps one item in the same source-agnostic shape returned by Get Feed Items per element. Use this when you already have an item id (e.g. from the list response, a webhook, or a saved reference) and want to refetch the latest version of just that item without scanning the feed.

GET /feeds/news/{feedId}/items/{itemId}

Request

Path parameters:

NameTypeDescription
feedIdstring (UUID)Feed identifier
itemIdstring (UUID)Feed item identifier (from the id field)

Query parameters:

NameTypeDefaultDescription
includestring-Comma-separated list of optional response sections to include. Currently supported: source. Unknown tokens return 400.

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

The response body wraps a single item in the same per-item shape as Get Feed Items — including id, newsPageId, the same strip-null semantics, and the same opt-in ?include=source block. See Get Feed Items above for the full field reference and per-platform source block shapes.

{
"success": true,
"data": {
"id": "item_3bNm58fwQ",
"newsPageId": "page_8aXp17vmY",
"title": "AI Startup Raises $100M Series B",
"description": "The company plans to expand its enterprise AI platform...",
"url": "https://techcrunch.com/2024/01/15/ai-startup-funding",
"imageUrl": "https://cdn.example.com/article-hero.jpg",
"publishedAt": "2024-01-15T11:30:00.000Z",
"createdAt": "2024-01-15T12:00:00.000Z",
"updatedAt": "2024-01-15T12:00:00.000Z"
}
}

Examples

Default:

curl "https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items/item_3bNm58fwQ" \
-H "Authorization: Bearer YOUR_API_KEY"

With per-platform source block:

curl "https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items/item_3bNm58fwQ?include=source" \
-H "Authorization: Bearer YOUR_API_KEY"

Errors

  • 400: Unknown include token, or malformed UUID.
  • 401: Missing or invalid API key.
  • 404: Feed or item not found, the item belongs to a different feed, or your organization has no access to the feed.

Submit Item Feedback

Submits feedback for a specific feed item. Use this to indicate whether an article was relevant or useful.

POST /feeds/news/{feedId}/items/{itemId}/feedback

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier
itemIdstringFeed item identifier (from the id field)

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Body:

{
"rating": "positive",
"comment": "This article was very relevant to my interests."
}

Parameters:

NameTypeRequiredDescription
ratingstringYesFeedback rating: positive, negative, or neutral
commentstringNoOptional comment explaining the feedback. Maximum 5000 characters.

Response

Status: 200 OK

{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440099"
}
}

Response object:

FieldTypeDescription
idstring (UUID)Unique feedback identifier

Examples

Positive feedback:

curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items/item_3bNm58fwQ/feedback \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rating": "positive",
"comment": "Great article, very relevant!"
}'

Negative feedback without comment:

curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items/item_3bNm58fwQ/feedback \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rating": "negative"
}'

Errors

  • 400: Invalid rating value or comment exceeds maximum length
  • 401: Missing or invalid API key
  • 404: Feed or item not found, or you don't have access to this feed

Notes

  • Feedback is additive: you can submit multiple feedback entries for the same item
  • You can only submit feedback for items in feeds you own or are subscribed to

Source Management

Add a Source

Adds a website, sitemap, or index page as a source for a feed. The source immediately begins monitoring for new content.

Important: When you add a source, Helix automatically initiates a 14-day backfill to populate your feed with recent articles.

POST /feeds/news/{feedId}/sources

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Body (varies by source type):

Website Source

Monitors all content from a domain.

{
"sourceType": "site",
"domain": "techcrunch.com"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "site"
domainstringYesDomain name without protocol (e.g., example.com, not https://example.com)

What happens:

  1. Helix creates a site record (or reuses existing)
  2. Begins crawling the domain to discover articles
  3. Starts 14-day backfill
  4. Monitors for new content continuously

Sitemap Source

Monitors a specific XML sitemap.

{
"sourceType": "sitemap",
"url": "https://techcrunch.com/news-sitemap.xml",
"siteId": "site_5dRu71lpS"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "sitemap"
urlstringYesFull URL to the sitemap. Must be publicly accessible.
siteIdstringYesSite identifier. Obtain by first creating a site source (use the returned sourceId).

Getting a siteId: Create a site source first. The response includes a sourceId field—use this value as the siteId for sitemap and index page sources.

# Step 1: Create a site source
curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-d '{"sourceType": "site", "domain": "example.com"}'
# Response includes: "sourceId": "site_5dRu71lpS"

# Step 2: Use that sourceId as siteId for sitemap
curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-d '{
"sourceType": "sitemap",
"url": "https://example.com/sitemap.xml",
"siteId": "site_5dRu71lpS"
}'

Index Page Source

Monitors a page that lists articles (e.g., category pages).

{
"sourceType": "siteIndexPage",
"url": "https://techcrunch.com/category/artificial-intelligence/",
"siteId": "site_5dRu71lpS"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "siteIndexPage"
urlstringYesFull URL to the index page.
siteIdstringYesSite identifier (same as sitemap sources).

What it monitors: The page at the URL is regularly checked for new article links. When new links appear, their content is extracted and added to your feed.

Instagram Source

Tracks posts and reels from an Instagram account. If the account isn't already registered in Helix, it's fetched from Instagram and created on the fly.

{
"sourceType": "instagram",
"username": "wcnctv"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "instagram"
usernamestringYesInstagram handle (with or without leading @). Case-insensitive.

Errors: 404 if the Instagram account doesn't exist or is private.

TikTok Source

Tracks videos from a TikTok account. Account is fetched from TikTok if not yet tracked.

{
"sourceType": "tiktok",
"username": "newsdaily"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "tiktok"
usernamestringYesTikTok handle (with or without leading @). Case-insensitive.

Errors: 404 if the TikTok account doesn't exist or is private.

Twitter / X Source

Tracks tweets from a Twitter / X account. Account is fetched if not yet tracked.

{
"sourceType": "twitter",
"username": "localreporter"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "twitter"
usernamestringYesTwitter handle (with or without leading @). Case-insensitive.

Errors: 404 if the Twitter account doesn't exist.

Facebook Source

Tracks content from a Facebook page, group, or profile. The source is fetched from Facebook if not yet tracked.

{
"sourceType": "facebook",
"facebookType": "page",
"identifier": "citynewspage"
}

Parameters:

NameTypeRequiredDescription
sourceTypestringYesMust be "facebook"
facebookTypestringYesOne of "page", "group", or "profile"
identifierstringYesFacebook page/group/profile identifier (handle or numeric id)

Errors: 404 if the Facebook source can't be found or accessed.

Response

Status: 201 Created

{
"success": true,
"data": {
"id": "src_6eVx82nqT",
"newsFeedId": "feed_2aKj39dkD",
"sourceType": "site",
"sourceId": "site_5dRu71lpS",
"createdAt": "2024-01-15T10:45:00.000Z",
"sourceDetails": {
"sourceType": "site",
"domain": "techcrunch.com"
}
}
}

Response object:

FieldTypeDescription
idstringUnique source identifier. Use when updating or deleting.
newsFeedIdstringFeed this source belongs to
sourceTypestringType: site, sitemap, or siteIndexPage
sourceIdstringImportant: For site sources, use this value as siteId when creating sitemap/index page sources.
createdAtstring (ISO 8601)When the source was added
sourceDetailsobjectEcho of the source configuration

Examples

Website source:

curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceType": "site",
"domain": "techcrunch.com"
}'

Sitemap source:

curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceType": "sitemap",
"url": "https://techcrunch.com/news-sitemap.xml",
"siteId": "site_5dRu71lpS"
}'

Index page source:

curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceType": "siteIndexPage",
"url": "https://techcrunch.com/category/startups/",
"siteId": "site_5dRu71lpS"
}'

Errors

  • 404: Feed not found
  • 409: Source already exists for this feed

List Sources

Retrieves all sources configured for a feed.

GET /feeds/news/{feedId}/sources

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true,
"data": [
{
"id": "src_6eVx82nqT",
"newsFeedId": "feed_2aKj39dkD",
"sourceType": "site",
"sourceId": "site_5dRu71lpS",
"createdAt": "2024-01-15T10:45:00.000Z"
},
{
"id": "src_9hZy15ruW",
"newsFeedId": "feed_2aKj39dkD",
"sourceType": "sitemap",
"sourceId": "stm_3fTw46kpM",
"createdAt": "2024-01-15T11:20:00.000Z"
}
]
}

Returns an array of source objects sorted by creation date (newest first).

Example

curl https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-H "Authorization: Bearer YOUR_API_KEY"

Update a Source

Enables or disables monitoring for a source without deleting it.

PATCH /feeds/news/{feedId}/sources/{sourceId}

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier
sourceIdstringSource identifier (from source id field, not sourceId field)

Headers:

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Body:

{
"enabled": false
}

Parameters:

NameTypeRequiredDescription
enabledbooleanYestrue to enable monitoring, false to disable

Behavior:

  • When disabled: Stops monitoring for new articles. Existing feed items remain.
  • When re-enabled: Resumes monitoring but does not backfill articles published while disabled.

Response

Status: 200 OK

{
"success": true,
"data": {
"id": "src_6eVx82nqT",
"newsFeedId": "feed_2aKj39dkD",
"sourceType": "site",
"sourceId": "site_5dRu71lpS",
"createdAt": "2024-01-15T10:45:00.000Z"
}
}

Example

# Disable a source
curl -X PATCH https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources/src_6eVx82nqT \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

# Re-enable later
curl -X PATCH https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources/src_6eVx82nqT \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'

Delete a Source

Permanently removes a source from a feed. Articles already in the feed remain.

DELETE /feeds/news/{feedId}/sources/{sourceId}

Request

Path parameters:

NameTypeDescription
feedIdstringFeed identifier
sourceIdstringSource identifier

Headers:

Authorization: Bearer YOUR_API_KEY

Response

Status: 200 OK

{
"success": true
}

Warning: This action is permanent. To temporarily stop monitoring, use the update endpoint instead.

Example

curl -X DELETE https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources/src_6eVx82nqT \
-H "Authorization: Bearer YOUR_API_KEY"

Error Responses

All endpoints use consistent error responses.

400 Bad Request

Invalid request parameters or body.

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Name is required"
}
}

Common causes:

  • Missing required fields
  • Invalid data types
  • Values outside allowed ranges

401 Unauthorized

Missing or invalid API key.

{
"success": false,
"error": "Authentication failed for strategy: api-key",
"code": "AUTHENTICATION_FAILED"
}

Common causes:

  • Missing Authorization header
  • Incorrect header format
  • Invalid API key

404 Not Found

Resource doesn't exist.

{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "News feed not found",
"resource": "News feed",
"id": "feed_2aKj39dkD"
}
}

Common causes:

  • Incorrect ID
  • Resource was deleted

409 Conflict

Resource already exists.

{
"success": false,
"error": {
"code": "CONFLICT",
"message": "News feed source already exists"
}
}

Common causes:

  • Attempting to add a duplicate source

500 Internal Server Error

Unexpected server error.

{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred"
}
}

If this persists: Retry the request


Best Practices

Use the siteId Pattern

When adding sitemaps or index pages for a domain:

  1. Create a site source first
  2. Save the returned sourceId
  3. Use that as siteId for related sources
# Create site source
RESPONSE=$(curl -s -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-d '{"sourceType": "site", "domain": "example.com"}')

SITE_ID=$(echo $RESPONSE | jq -r '.data.sourceId')

# Now create sitemap using that siteId
curl -X POST https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/sources \
-d "{
\"sourceType\": \"sitemap\",
\"url\": \"https://example.com/sitemap.xml\",
\"siteId\": \"$SITE_ID\"
}"

Paginate Large Result Sets

Always use pagination for feeds with many articles:

async function getAllFeedItems(feedId) {
const allItems = [];
let offset = 0;
const limit = 100; // Max allowed
let hasMore = true;

while (hasMore) {
const response = await fetch(
`https://api.feeds.onhelix.ai/feeds/news/${feedId}/items?limit=${limit}&offset=${offset}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);

const result = await response.json();
allItems.push(...result.data.items);

hasMore = result.data.pagination.hasMore;
offset += limit;
}

return allItems;
}

Use Date Filters

Filter by date range to reduce response size:

# Get today's articles
TODAY=$(date -u +%Y-%m-%dT00:00:00Z)
curl "https://api.feeds.onhelix.ai/feeds/news/feed_2aKj39dkD/items?since=$TODAY" \
-H "Authorization: Bearer YOUR_API_KEY"