Content Ingestion
Mirror an external blog or knowledge base into the widget via RSS or signed webhook push
Instead of authoring help articles and news posts by hand, you can ingest them from an external source. Two source kinds feed both the News and Help tabs:
| Kind | Direction | Use when |
|---|---|---|
| RSS | Wexio polls your feed | You publish a public RSS/Atom feed (blog, changelog, docs). |
| Webhook push | Your system posts to Wexio | You'd rather push on publish than be polled. |
One source can feed multiple widgets. Both kinds share the same field-mapping and lifecycle.
Source lifecycle
Sources are created disabled so you can test the mapping before going live:
- Create the source (RSS feed URL, or a webhook connection).
- Test it — RSS fetches one item; webhook returns the last captured payload.
- Preview the field mapping — each target column shows its resolved value.
- Activate — validation confirms the required fields (
externalId,title,body) resolve, then flips the source live.

Deactivating a source is a kill switch (the config is preserved). Deleting a source removes only the source row — already-ingested articles survive.
RSS
Standard RSS 2.0 and Atom work out of the box with the default field map. The poll cadence is configurable (15–1440 minutes, default 60); Wexio backs off when the feed returns 304 Not Modified.
Only public https:// feeds are supported. At fetch time, a server-side guard blocks private/loopback/link-local addresses and rejects redirects, with a 10-second timeout. Each poll ingests up to 1000 items.
Wexio RSS extension
For stable slugs that survive label edits, add the Wexio namespace to your feed:
<rss xmlns:wexio="https://wexio.io/rss-extension">
<channel>
<item>
<wexio:slug>hello-world</wexio:slug>
<wexio:category slug="product-launches">Product Launches</wexio:category>
<wexio:tag slug="multi-tenant">Multi-tenant</wexio:tag>
</item>
</channel>
</rss>Webhook push
Point your system's outbound webhook at the inbound endpoint and sign the body. The canonical payload is a list of items:
{
"items": [
{
"id": "post-1234",
"title": "Acme launches multi-tenant billing",
"body": "<p>HTML or markdown body…</p>",
"bodyFormat": "html",
"excerpt": "One-sentence summary shown in the feed card.",
"slug": "acme-launches-multi-tenant-billing",
"locale": "en",
"sourceUrl": "https://blog.acme.io/posts/multi-tenant-billing",
"publishedAt": "2026-05-01T10:00:00Z",
"coverImageUrl": "https://cdn.acme.io/billing.png",
"categories": [{ "slug": "product", "label": "Product" }],
"tags": [{ "slug": "billing", "label": "Billing" }]
}
]
}Help items use the same shape but carry a folder (with optional parentSlug) instead of categories/coverImageUrl.
Signing
Send an HMAC-SHA256 of the raw body (before JSON parsing), keyed with the connection's signing secret, in the X-Webhook-Signature header:
const signature = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(rawBody) // bytes, before JSON.parse
.digest("hex");
// header: X-Webhook-Signature: <signature>| Header | Purpose |
|---|---|
Content-Type: application/json | Required. |
X-Webhook-Signature | HMAC-SHA256 of the raw body. Mismatch is rejected with 403. |
X-Idempotency-Key | Recommended. The result is cached for 24h; a resend with the same key returns a replay without re-ingesting. |
Field mapping
If your payload doesn't match the canonical shape, map each target column to a path in your data (dot-notation). A few notes:
externalIdis the dedupe key (with the source). Re-pushing the sameexternalIdis a no-op, so your operators' manual edits survive.bodyFormatishtmlormarkdown. Help auto-detects when unset; markdown is converted to HTML on ingest.- News-only fields:
coverImageUrl,audienceMode,categories. Help-only:folder,folderAncestors.
Items deleted upstream are not auto-removed from Wexio — delete them in the dashboard if needed.
Outbound: news.published
When a news post is published (natively or by the scheduler), Wexio emits a news.published outbound webhook, so your own systems can react to it.