API Reference
Complete API reference for Helix News Feeds. All endpoints use JSON for request and response bodies.
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:
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Feed name. Minimum 1 character. |
description | string | Yes | Feed 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:
| Field | Type | Description |
|---|---|---|
id | string | Unique feed identifier. Use this when adding sources or retrieving items. |
name | string | Feed name |
description | string | Feed description |
createdAt | string (ISO 8601) | When the feed was created |
updatedAt | string (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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed 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:
| Name | Type | Required | Description |
|---|---|---|---|
name | string | No | Updated feed name |
description | string | No | Updated feed description |
enabled | boolean | No | Enable 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed identifier |
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Number of items to return. Range: 1-100. |
offset | integer | 0 | Number of items to skip. Use for pagination. |
since | string (ISO 8601) | - | Only items created after this date. Example: 2024-01-15T00:00:00Z |
until | string (ISO 8601) | - | Only items created before this date. Example: 2024-01-20T23:59:59Z |
include | string | - | 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.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Stable feed-item identifier. Use this for client-side dedup, the singular item endpoint, and the feedback endpoint. |
newsPageId | string | yes | Stable identifier of the underlying news article. The same value across all feeds containing this article — use it to correlate items across feeds. |
title | string | no | Headline / title of the original content (omitted when not available). |
description | string | no | Article body / caption / tweet text — content varies by source (omitted when empty). |
url | string | no | Canonical link back to the original content. |
imageUrl | string | no | Best representative image (article hero, post media, or video thumbnail). |
publishedAt | string (ISO 8601) | no | Original publish time on the source platform. Omitted when unknown. |
createdAt | string (ISO 8601) | yes | When the item entered the feed. |
updatedAt | string (ISO 8601) | yes | Last update. |
source | object | no | Per-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
authorfield. Publisher information ("who posted this") lives inside thesourceblock 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"
| Field | Type | Description |
|---|---|---|
type | string | Always "site". |
url | string | Canonical URL to the page. |
Publisher object (carried by each of the four social source blocks below as publisher):
| Field | Type | Description |
|---|---|---|
name | string | Display name. Always present. Falls back to username for IG/TikTok/Twitter when the platform stores no distinct display name. |
username | string | Raw handle (no @ prefix). Omitted only when the platform does not expose one (rare on Facebook pages). |
avatarUrl | string | Profile picture URL (omitted when not available). |
type | string | Facebook only — page, group, or profile. Omitted for Instagram, TikTok, and Twitter. |
source.type: "instagram"
| Field | Type | Description |
|---|---|---|
type | string | Always "instagram". |
subtype | string | post or reel. |
permalinkUrl | string | Public Instagram URL. |
caption | string | Post caption (omitted when empty). |
mediaUrl | string | Image or video URL (omitted when empty). |
thumbnailUrl | string | Thumbnail URL (omitted when empty). |
publisher | object | See Publisher object above. |
source.type: "tiktok"
| Field | Type | Description |
|---|---|---|
type | string | Always "tiktok". |
subtype | string | video. |
permalinkUrl | string | Public TikTok URL. |
caption | string | Video caption (omitted when empty). |
mediaUrl | string | Video URL (omitted when empty). |
thumbnailUrl | string | Thumbnail URL (omitted when empty). |
publisher | object | See Publisher object above. |
source.type: "twitter"
| Field | Type | Description |
|---|---|---|
type | string | Always "twitter". |
subtype | string | tweet, retweet, quote, or reply. |
permalinkUrl | string | Public Twitter URL. |
text | string | Tweet text (omitted when empty). |
mediaUrl | string | Attached media URL (omitted when empty). |
publisher | object | See Publisher object above. |
source.type: "facebook"
| Field | Type | Description |
|---|---|---|
type | string | Always "facebook". |
subtype | string | post, video, photo, link, or event. |
permalinkUrl | string | Public Facebook URL (omitted when not available). |
text | string | Post text / caption (omitted when empty). |
mediaUrl | string | Attached media URL (omitted when empty). |
publisher | object | See 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:
| Field | Type | Description |
|---|---|---|
limit | integer | Items per page (as requested) |
offset | integer | Current offset (as requested) |
hasMore | boolean | Whether 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 shape | Per-content-type — { type, data: {...} } envelope. | Source-agnostic — same keys for every content type. |
type discriminator | At the root. | Moved to source.type (only present with ?include=source). |
| Null fields | Emitted as null. | Omitted from response. |
| Internal database ids | Exposed (sitePageId, instagramContentId, account.id, etc.). | Hidden — consumers use the root id and the permalinkUrl / url. |
?include | not 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed identifier |
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Number of items to return. Range: 1-100. |
offset | integer | 0 | Number of items to skip. Use for pagination. |
since | string (ISO 8601) | - | Only items created after this date. Example: 2024-01-15T00:00:00Z |
until | string (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:
| Field | Type | Description |
|---|---|---|
id | string | Unique item identifier |
newsPageId | string | Internal reference to the news page |
type | string | Content type: site, instagram, tiktok, twitter, or facebook |
data | object | Item data. Shape depends on type — see per-type schemas below. |
createdAt | string (ISO 8601) | When the item was added to the feed |
updatedAt | string (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):
| Field | Type | Description |
|---|---|---|
data.sitePageId | string | Internal site page identifier |
data.sitePageVersionId | string | Version of the page this item refers to |
data.url | string | Article URL |
data.title | string|null | Article headline |
data.description | string|null | Article summary |
type: "instagram":
| Field | Type | Description |
|---|---|---|
data.instagramContentId | string | Internal Instagram content id |
data.code | string | Instagram shortcode |
data.type | string | post or reel |
data.permalinkUrl | string | Public Instagram URL |
data.caption | string|null | Post caption |
data.mediaUrl | string|null | Image or video URL |
data.thumbnailUrl | string|null | Thumbnail URL (for videos/reels) |
data.publishedAt | string (ISO 8601) | When originally posted |
data.account.id | string | Account id |
data.account.username | string | @username |
data.account.fullName | string|null | Display name |
data.account.profilePicUrl | string|null | Avatar URL |
type: "tiktok":
| Field | Type | Description |
|---|---|---|
data.tiktokContentId | string | Internal TikTok content id |
data.tiktokId | string | TikTok's video id |
data.type | string | video |
data.permalinkUrl | string | Public TikTok URL |
data.caption | string|null | Video caption |
data.mediaUrl | string|null | Video URL |
data.thumbnailUrl | string|null | Thumbnail URL |
data.publishedAt | string (ISO 8601) | When originally posted |
data.account.id | string | Account id |
data.account.username | string | @username |
data.account.displayName | string|null | Display name |
data.account.profilePicUrl | string|null | Avatar URL |
type: "twitter":
| Field | Type | Description |
|---|---|---|
data.twitterContentId | string | Internal Twitter content id |
data.tweetId | string | Twitter's tweet id |
data.type | string | tweet, retweet, quote, or reply |
data.permalinkUrl | string | Public Twitter URL |
data.text | string|null | Tweet text |
data.mediaUrl | string|null | Attached media URL |
data.publishedAt | string (ISO 8601) | When originally posted |
data.account.id | string | Account id |
data.account.username | string | @username |
data.account.displayName | string|null | Display name |
data.account.profileImageUrl | string|null | Avatar URL |
type: "facebook":
| Field | Type | Description |
|---|---|---|
data.facebookContentId | string | Internal Facebook content id |
data.facebookId | string | Facebook's internal content id |
data.type | string | post, video, photo, link, or event |
data.permalinkUrl | string|null | Public Facebook URL (may be unavailable for some post types) |
data.text | string|null | Post text / caption |
data.mediaUrl | string|null | Attached media URL |
data.publishedAt | string (ISO 8601) | When originally posted |
data.source.id | string | Facebook source id (page/group/profile) |
data.source.name | string | Source display name |
data.source.username | string|null | Source 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:
| Field | Type | Description |
|---|---|---|
limit | integer | Items per page (as requested) |
offset | integer | Current offset (as requested) |
hasMore | boolean | Whether 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:
| Name | Type | Description |
|---|---|---|
feedId | string (UUID) | Feed identifier |
itemId | string (UUID) | Feed item identifier (from the id field) |
Query parameters:
| Name | Type | Default | Description |
|---|---|---|---|
include | string | - | 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: Unknownincludetoken, 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed identifier |
itemId | string | Feed 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:
| Name | Type | Required | Description |
|---|---|---|---|
rating | string | Yes | Feedback rating: positive, negative, or neutral |
comment | string | No | Optional comment explaining the feedback. Maximum 5000 characters. |
Response
Status: 200 OK
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440099"
}
}
Response object:
| Field | Type | Description |
|---|---|---|
id | string (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 length401: Missing or invalid API key404: 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "site" |
domain | string | Yes | Domain name without protocol (e.g., example.com, not https://example.com) |
What happens:
- Helix creates a site record (or reuses existing)
- Begins crawling the domain to discover articles
- Starts 14-day backfill
- 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "sitemap" |
url | string | Yes | Full URL to the sitemap. Must be publicly accessible. |
siteId | string | Yes | Site 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "siteIndexPage" |
url | string | Yes | Full URL to the index page. |
siteId | string | Yes | Site 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "instagram" |
username | string | Yes | Instagram 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "tiktok" |
username | string | Yes | TikTok 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "twitter" |
username | string | Yes | Twitter 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:
| Name | Type | Required | Description |
|---|---|---|---|
sourceType | string | Yes | Must be "facebook" |
facebookType | string | Yes | One of "page", "group", or "profile" |
identifier | string | Yes | Facebook 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:
| Field | Type | Description |
|---|---|---|
id | string | Unique source identifier. Use when updating or deleting. |
newsFeedId | string | Feed this source belongs to |
sourceType | string | Type: site, sitemap, or siteIndexPage |
sourceId | string | Important: For site sources, use this value as siteId when creating sitemap/index page sources. |
createdAt | string (ISO 8601) | When the source was added |
sourceDetails | object | Echo 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 found409: Source already exists for this feed
List Sources
Retrieves all sources configured for a feed.
GET /feeds/news/{feedId}/sources
Request
Path parameters:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed identifier |
sourceId | string | Source identifier (from source id field, not sourceId field) |
Headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Body:
{
"enabled": false
}
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
enabled | boolean | Yes | true 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:
| Name | Type | Description |
|---|---|---|
feedId | string | Feed identifier |
sourceId | string | Source 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
Authorizationheader - 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:
- Create a
sitesource first - Save the returned
sourceId - Use that as
siteIdfor 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"