Skip to main content

Quickstart

Create a destination, subscribe it to events, verify the endpoint is wired correctly, and receive your first delivery. Every request below is runnable against /events/*.

Prerequisites

  • A Helix API key. See Authentication.
  • An HTTPS endpoint you control that can receive a POST request.

Base URL: https://api.feeds.onhelix.ai

Step 1: Create a destination

curl -X POST https://api.feeds.onhelix.ai/events/destinations \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Newsroom CMS",
"transport": "webhook",
"config": { "url": "https://cms.acme.com/hx" }
}'

The response includes your signing secret in full — store it now. It is not a show-once secret: the secrets endpoint returns every still-valid secret in full at any time.

The response also includes a validation block from a pre-flight reachability probe. An unreachable URL still saves; only a non-HTTPS or unsafe URL is rejected. See API Reference.

{
"success": true,
"data": {
"id": "8f14e45f-ceea-467e-adde-3fb5c25adfcd",
"status": "enabled",
"secrets": [{ "secret": "whsec_…", "expiresAt": null }],
"validation": {
"reachable": true,
"statusCode": 200,
"responseTimeMs": 142
}
}
}

Save the returned id — you'll need it for the next step. You can also set your own externalId in the request body to reference this destination by an id from your own system instead of the server-assigned one — see {ref} resolution.

Step 2: Subscribe to events

Declare which events this destination should receive. This example scopes to every news.* event across the whole organization:

curl -X POST https://api.feeds.onhelix.ai/events/destinations/{id}/subscriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"eventTypes": ["news.*"],
"scopeKind": "all"
}'

To scope to specific feeds instead, use scopeKind: "feeds" with a feeds array — see Concepts.

See Event Types for the full catalog of eventTypes values, or browse the per-type pages starting with news.item.added.

Step 3: Verify signature handling

Implement signature verification now, then prove it with a test delivery (below) before the first real event fires:

Your endpoint's contract

Respond within 30 seconds. Any 2xx status is success; everything else is a failure. The response body is never read — acknowledge first, then do the real work asynchronously, as the handler below does. See Reliability: The contract for the full rules.

const express = require('express');
const { Webhook } = require('standardwebhooks');

const secret = 'whsec_...'; // the whsec_… value from Step 1
const wh = new Webhook(secret);

const app = express();

app.post(
'/hx',
express.raw({ type: 'application/cloudevents+json' }),
(req, res) => {
try {
wh.verify(req.body, req.headers);
} catch (err) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('OK');
// process asynchronously below
}
);

See Signature Verification for the full explanation and other language libraries.

Now send yourself a signed test delivery. It goes through exactly the path a real event takes — same envelope, same signed headers, same custom headers — and tells you what your endpoint answered:

curl -X POST https://api.feeds.onhelix.ai/events/destinations/{ref}/test \
-H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"delivered": true,
"statusCode": 200,
"responseTimeMs": 142,
"error": null,
"webhookId": "…",
"event": { "type": "delivery.test", "id": "…", "time": "…" }
}
}

delivered: false with a statusCode of 401 means your endpoint rejected the signature; null with an error means it never answered. The event type is delivery.test — accept it (verify, return 2xx) and otherwise ignore it. See Reliability: Test deliveries.

Step 4: Receive a delivery

This step needs real feed activity to trigger it. If you don't already have a feed producing content, set one up first: see News Feeds Quickstart or Event Feeds Quickstart, then add or update an item in a feed your subscription covers.

Once a matching event occurs (a new article lands in a subscribed feed, for example), your endpoint receives a POST with a CloudEvents envelope. Give it a minute or two: delivery is debounced per subject (120 seconds by default), so a freshly created destination seeing nothing for the first couple of minutes is expected, not broken.

{
"specversion": "1.0",
"type": "news.item.added",
"source": "/feeds/news/{feedId}",
"subject": "123e4567-e89b-12d3-a456-426614174000",
"id": "456e7890-a12b-34c5-d678-901234567890",
"time": "2024-01-15T10:30:00.000Z",
"datacontenttype": "application/json",
"data": {
"feedId": "123e4567-e89b-12d3-a456-426614174000",
"id": "123e4567-e89b-12d3-a456-426614174000",
"newsPageId": "123e4567-e89b-12d3-a456-426614174000"
}
}

Use the envelope id as your idempotency key — it is stable across retry attempts of the same delivery. A replay reuses that same id, though, so a naive "skip if I've already seen this id" store will also silently skip a replay you actually wanted reprocessed — see Reliability: Idempotency for how to key your dedupe so a replay still gets through. The data payload is intentionally minimal; fetch full content from the corresponding feed API. See Concepts for the envelope and payload philosophy.

Next steps

  • Concepts — envelope, type taxonomy, wildcards, feed scoping, debounce.
  • Reliability — retries, auto-disable, replay, backfill.
  • API Reference — the complete /events/* surface.