Skip to main content
Create a watch with POST /v1/{source}/watches and provide a webhook_url. When matches change, Nephia POSTs an event payload to your endpoint. webhook_url is optional. A watch created without one polls, bills and records its matches exactly the same; it simply pushes nothing. Read those matches with GET /v1/{source}/watches/{id}/events, which is free.

Event types

Payload envelope

Every event uses the same shape. Unused fields are null. ai is the agent step’s reading of the event. It is null unless the watch was created with an ai step — see Agent step on a watch below. analysis is the only optional key in the body: it is present when something read the item, and absent otherwise — see The analysis key below.

Two dates, and which is which

occurredAt is when Nephia collected the item — the instant the tick that caught it ran. publishedAt is when the platform says the item was published. They are usually minutes apart and sometimes years. A watch polling every 15 minutes that meets a two-year-old Reddit thread on today’s page delivers it with today’s occurredAt and a 2024 publishedAt. Use occurredAt to order or de-duplicate a stream you are syncing, and to filter with since and until — those read occurredAt, so nothing you have already been delivered can arrive behind you. Use publishedAt to answer “when was this said”: grouping mentions by day, charting them over time, deciding whether something is fresh. publishedAt is null when the source gave no real date. Two cases: an AI answer has no publication date at all (it is generated the moment we ask, so its occurredAt is its date), and a YouTube video caught through search reports a relative age — “4 years ago” — which we will not turn into a timestamp we cannot stand behind. Fall back to occurredAt when you need a date for every item.

The analysis key

A watch whose owning search has analysis turned on delivers one extra key, after ai:
Both are read on one pass, so turning analysis on costs one charge and answers both. null inside the object means not read — never “we looked and found nothing”. That verdict has its own value in each vocabulary: neutral for an item that takes no side, other for an item with no recognisable intent. The key is absent, not null, on an event nothing classified. Read it as event.analysis?.intent rather than branching on the key’s existence for anything else. Every other key in the body is always present, and this one is the exception on purpose: an object of two nulls on every delivery would say nothing. The same object comes back from GET /v1/{source}/watches/{id}/events, so a replay and a delivery agree field for field.

X tweet.created

Vinted listing.price_changed

Reddit post.created

Reddit reddit_comment.created

A comment travels in the same post object a submission does, told apart by kind. title is the parent submission’s title, selftext is what the comment said, and id carries Reddit’s t1_ prefix.
A consumer subscribed to post.created never receives one of these: a comment has no submission’s shape to offer it. See Reddit.

Youtube video.created

Bluesky bluesky_post.created

See Bluesky.

Hacker News hn_item.created

On a comment, title is the parent story’s title and url is nullhnUrl is where the comment is read. See Hacker News.

RSS article.created

summary is text, never HTML. See RSS & News.

AI answers answer.changed

mentioned and cited are different questions and a brand can be either without the other — see AI answers. The same shape arrives on answer.created, term.cited and term.uncited; only type differs, and on a first run previous is null.

Agent step on a watch

A watch can be created with an ai step: one instruction and one flat schema of your own fields, applied to every event the watch emits. The answer arrives on the event, in the ai block.
Events from that watch carry the reading:

Delivery waits for the reading

A watch with an ai step holds its delivery until the step answers, up to 120 seconds. You receive one message per event, with ai filled in — never a first message without the reading and a second one with it. The event is never lost. If the step times out or fails, the event is delivered anyway with ai.output: null and ai.status set to timeout or failed. Treat a missing reading as “no answer”, not as an error to retry: the event itself is complete. Watches without an ai step are unaffected: they deliver immediately, with ai: null.

Schema and rates

The schema is a flat object of 1–12 fields, each string, number, boolean or enum. Every field can answer null — that is a real answer, not an error. See AI for the full subset and the credit rate.

Signature verification

Each delivery includes an X-Signature header of the form t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of "<t>.<raw JSON body>" using your account’s webhook signing secret. The timestamp prevents replay attacks: reject deliveries whose t is more than 5 minutes from now. Your signing secret is per-account — find it on the API Keys page of the dashboard. With the SDK (recommended):
Manual verification:

Retries

Failed deliveries (non-2xx or network error) retry with backoff: immediate, +30s, +120s (3 attempts total).
In n8n, the official Nephia Trigger does all of this for you: it creates and deletes the watch, verifies the signature, and drops the repeats — with a poll mode for instances that are not reachable from the internet.

Replay events

Fetch historical events for a watch (free). This is also how you read a watch created without a webhook_url:
Events are kept for 90 days. A since older than that returns what is left, not an error — the rest has aged out. The window is the same for every plan and every source.Ninety days is far longer than a replay needs: a delivery that fails is retried for 48 hours, and a since you set from your own last-seen event is usually minutes or hours behind. If you need events beyond that, store them on receipt — the webhook body and the replay body are the same envelope, so nothing is lost by writing the one you are already handed.Retention is not the only way events end. A replay still reaches the events of a retired Query — DELETE /v1/queries/{id} without purge stops the polling and keeps the record — but not those of a purged one, which DELETE /v1/queries/{id}?purge=true deletes outright. If you replay against a Query somebody may delete, store what you receive.