Create a feed
Register an RSS or Atom URL. Emit polls it on a schedule (or on a webhook ping), tracks
which items it has already seen, and emails any new <item>
to your confirmed subscribers from your verified domain.
Each call creates a new feed and returns 201 Created. The same URL can be
registered more than once on an account.
curl -X POST https://api.rssemit.com/v1/feeds \ -H "Authorization: Bearer $EMIT_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://blog.dev/rss.xml", "from_email": "posts@blog.dev", "schedule": "on_publish" }'
{ "id": "3f8a1c2e-9b4d-4e7a-bf12-6c0d9a2e7f31", "url": "https://blog.dev/rss.xml", "title": null, "schedule": "on_publish", "from_email": "posts@blog.dev", "active": true, "last_polled_at": null, "last_status": null, "last_error": null, "digest_hour": 9, "digest_weekday": 0, "digest_tz": "UTC", "created_at": "2026-05-25T20:30:29Z" }
Body parameters #
| Field | Type | Description |
|---|---|---|
| url required | string · url | An HTTP(S) URL returning RSS 2.0 or Atom 1.0. |
| from_email required | string · email | Sender address. Its domain must be verified — see POST /v1/domains. The local part can be anything you own. |
| schedule optional | enum |
One of on_publish, daily, or weekly.
Default: on_publish (email each new item as it appears).
daily / weekly batch new items into a digest.
|
| title optional | string | A display name for the feed. Defaults to the feed's own title once polled. |
| template_html optional | string · html | A raw HTML string that overrides the default email layout for this feed. Omit to use Emit's maintained default template. |
| digest_hour optional | integer |
Hour of day (0–23) to send the digest. Only used for
daily / weekly schedules. Default: 9.
|
| digest_weekday optional | integer |
Day of week (0 = Monday … 6 = Sunday) for the
weekly digest. Default: 0.
|
| digest_tz optional | string · tz |
IANA timezone (e.g. America/New_York) that digest_hour /
digest_weekday are interpreted in. Default: UTC.
|
ETag +
Last-Modified returned by your feed and replays them on every poll. If your
origin responds 304, the request is free and we don't re-parse — 92%
of polls land here in practice. Make sure your CDN passes these headers.
Returns #
A feed object. The id is stable and safe to store — we never
recycle it, even after a delete.
Status codes
Smart feeds (watchers): anything → feed #
A smart feed — a watcher in the API — is the ingest half of the pipe:
sources + filter → feed. Describe an interest in plain language and emit
discovers matching sources, monitors them on your cadence, scores every new item against
the prompt, and serves the survivors at stable /w/{token}/atom.xml and
/w/{token}/feed.json
URLs. Or skip discovery and bring your own sources — feed URLs, or plain pages we watch by
link diffing — with an optional filter on top.
curl -X POST https://api.rssemit.com/v1/watchers \ -H "Authorization: Bearer $EMIT_KEY" \ -d '{ "prompt": "security advisories affecting postgres or redis", "cadence": "6h", "threshold":"balanced" }' # filter feeds you already have (no discovery): curl -X POST https://api.rssemit.com/v1/watchers \ -H "Authorization: Bearer $EMIT_KEY" \ -d '{ "prompt": "only items about breaking changes or deprecations", "sources": ["https://blog-a.dev/rss.xml", "https://blog-b.dev/atom.xml"], "discover": false }' # broadcast the feed as a daily email digest: curl -X POST https://api.rssemit.com/v1/watchers/$ID/pipe \ -H "Authorization: Bearer $EMIT_KEY" \ -d '{"from_email": "digest@yourdomain.dev", "schedule": "daily"}'
Worth knowing: a source's first check records a silent baseline (no
back-catalog blasts); filtered-out items stay auditable via
GET /v1/watchers/{id}/items?include_suppressed=true with a score and one-line
reason each; POST …/items/{id}/feedback (more/less)
tunes the threshold; syndicated duplicates collapse on canonical URL; and a
summarize toggle writes an LLM summary onto each emitted item. New items also
fan out to your
webhook endpoints as
watcher.item events and to any
Slack/Discord sinks subscribed to
the feed. Filtering meters the same credit balance as sending: 1 credit per 5 judged
items, 1 per summary, 25 credits per explicit discovery re-run, 2 credits per JS-rendered
page check (when enabled); creation, polling, and feeds out are free.
MCP server #
Emit hosts a remote MCP server at https://api.rssemit.com/mcp — there's
nothing to install. Point any MCP-aware client (Claude Code, Cursor, Codex) at the URL
with your API key. It exposes create_account, account,
verify_domain, connect_feed, add_subscriber,
import_subscribers, top_up, and send_broadcast as
tools.
{ "mcpServers": { "emit": { "type": "http", "url": "https://api.rssemit.com/mcp", "headers": { "Authorization": "Bearer emit_live_…" } } } }
Authorization header — the same auth, validation, and rate
limits as the REST API. Your subscribers' data is never proxied through a third
party, and there's no package to keep updated.
Claude Code skill #
The skill is a single static file at https://rssemit.com/skill.md. Save it
into ~/.claude/skills/ and Claude Code will know how to wire Emit into any
blog repo — it reads your CLAUDE.md, finds your RSS feed, verifies your
sending domain (DKIM/SPF/DMARC), imports subscribers, and sends the first broadcast.
mkdir -p ~/.claude/skills/emit curl -fsSL https://rssemit.com/skill.md \ -o ~/.claude/skills/emit/SKILL.md # Then, in any repo: claude "add a newsletter to this blog using emit"