> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nephia.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Conventions for the Nephia product API.

## Base URL

```
https://api.nephia.cc
```

Every endpoint on this page is called against that host, and the API playground
sends there too.

## Authentication

Send your API key in every request:

```
x-api-key: YOUR_API_KEY
```

See [Authentication](/authentication) for key management.

## What this API is

A **[keyword](/keywords)** polls the live Sources on an interval, keeps what matches, reads each
mention for sentiment and intent, sorts it into your buckets and answers your own
agent step over it. This API is both halves of getting that back:

* **Pull** with `GET /v1/mentions` across the whole Account (`?keyword=<id>` narrows it
  to one), or `GET /v1/keywords/{id}/results` per keyword.
* **Count** with `GET /v1/mentions/stats`: how many mentions per day, hour,
  Source, sentiment, intent, author, term or keyword, in one call and with the
  numbers Insights shows. Count there rather than by paging.
* **Push**: signed webhook events and delivery channels. See
  [Webhooks](/webhooks).
* **Replay** with `GET /v1/keywords/{id}/events`: the same events, each in the body its
  webhook delivers, for code that has no endpoint or was down. When something looks
  wrong, `GET /v1/keywords/{id}/activity` lists every check and every delivery. Both
  are free.
* **Ask once** with `POST /v1/explore`: one question across the Sources you
  name, without creating a keyword. It is priced first by
  `POST /v1/explore/estimate`, answers mentions, and is kept: re-read it free
  with `GET /v1/mentions?run={id}`. See [Explore](/explore).

And the management around it: create, estimate, edit, pause and resume the keywords
themselves, run [AI passes](/ai) over items you name, and read your credit
balance.

## Pagination

Mention reads are cursor-based: the response carries an opaque `nextCursor`,
which you pass back unchanged on the next request. Its absence means the last
page. A keyword's `/events`, `/activity` and `/ai-answers/runs` are bounded by `since`
and `limit` instead, and `GET /v1/vinted/items/{id}/price-history` by `limit`, `from`
and `to`.

## Filters

Every reading filter follows one rule: **repeat a key to OR its values, combine
keys to AND them.** `?sentiment=negative&sentiment=question&source=reddit` is
"negative or a question, on Reddit".

| Key | What it selects |
| - | - |
| `source` | The Sources to read: `reddit`, `x`, `hackernews`… Absent means every Source your keywords poll. |
| `intent` | What the analysis pass read the mention as: `purchase_intent`, `comparison`, `question`, `complaint`, `praise`, `other`. `unread` selects what nothing has classified yet. |
| `sentiment` | The reading itself: `positive`, `neutral`, `negative`, `question`, `mixed`, plus `unread`. |
| `author` | The accounts that posted. Matched **exactly**. |

A handle is the account name **as the Source writes it** — no leading `@`, no
`u/`, and case is kept: `alice`, `alice@mastodon.social`, `Some-Repo-Owner`.
`author` is a filter, not a search; use `q` for text. A handle you have never
seen returns an empty page rather than an error, and a mention with no author
never matches — not every Source carries a byline, and none carried one before
author extraction shipped for it.

Filtering on `intent`, `sentiment` or `author` reads the polled stream only:
items kept from a one-off Explore run carry no reading and no author.

## Windows

Reads over time take an ISO-8601 `since`. Leave it out and you get a default
window (24 hours for `/v1/mentions`, 30 days for a keyword's results) and the
response **echoes back** the `since` it actually read, so you never have to guess
which window you got.

### `occurredAt` and `publishedAt`

A mention carries two dates, and `since` and `until` both read the first one.

`occurredAt` is when **Nephia collected** it — the instant the tick that caught
it ran. `publishedAt` is when the **platform** says it was published. A keyword
meeting a two-year-old thread on today's page reports today for one and 2024 for
the other.

Windowing on collection is what makes a sync loop safe: pass the `since` a
response echoed back and nothing you have already read can arrive behind you.
Windowing on publication could not promise that — an old post caught tomorrow
would land in a window you already closed.

So filter with `occurredAt`, and group, chart or age with `publishedAt`.
`publishedAt` is `null` where the source gives no real date: an AI answer has
none, and a YouTube video found through search reports a relative age ("4 years
ago") rather than a timestamp. Fall back to `occurredAt` when you need a date on
every row.

## What costs credits

Reading your own mentions is free. These meter:

* `mode=semantic` on `/v1/mentions` and `/v1/keywords/{id}/results`: searching by
  meaning rather than by substring calls an embedding provider. Charged at the
  same rate, through the same ten-minute cache, as the dashboard: re-asking the
  same question inside the window costs nothing.
* `GET /v1/mentions/{id}/similar`: the mentions closest in meaning to one you
  already have. Charged per mention asked about, through the same ten-minute
  cache; asking about a different mention charges again.
* `POST /v1/analyses` — see [AI](/ai).
* `POST /v1/explore`: each search is charged at its Source's explore rate when
  it runs, and a search that fails is not charged. `POST /v1/explore/estimate`
  gives the figure first, for free. See [Explore](/explore).

Everything else on this surface is a read of data you already paid to collect.
See [Credits](/credits).

## Casing

Request bodies are `snake_case` and responses are `camelCase`, with one
deliberate exception: the bodies of `POST /v1/keywords` and
`PATCH /v1/keywords/{id}` are **camelCase**, matching the keyword object those
endpoints return. So are the bodies of `POST /v1/explore` and its estimate,
which carry a keyword's criteria. A keyword is the one object you round-trip (read it, change a
field, send it back), and that only works if the two spellings agree.

## Absent is not null

On `PATCH /v1/keywords/{id}`, a key you do not send is left alone; a key sent as
`null` clears it. The difference is load-bearing: a search whose terms, filters
or market change is started over, and its first poll records
what currently matches without emitting it. The mentions caught before the change
stay on the keyword. A new interval or webhook applies in place
and starts nothing over. The response's `resetSearches` names the searches
that were started over.

## Rate limits

Every `/v1/*` call counts against a per-Account, per-minute request quota set by your plan
(60/min on Free, up to 1,200/min on Pro). Responses carry `RateLimit` and `RateLimit-Policy`
headers (IETF draft-7); over the quota you get **429** with `Retry-After`. See [Limits](/limits).

## Sources

Each Source page describes its **coverage**: what a keyword on it
captures, and what arrives in each event:

* [X](/sources/x) — tweets matching a search query
* [Reddit](/sources/reddit) — posts from search or a subreddit
* [Youtube](/sources/youtube) — videos from a search or a channel
* [Bluesky](/sources/bluesky) — posts by term and/or author
* [Hacker News](/sources/hackernews) — stories and comments matching a term
* [RSS & News](/sources/rss) — any feed on the web, plus news by term
* [AI answers](/sources/ai-answers) — what ChatGPT, Gemini and Perplexity say about a prompt
* [Vinted](/sources/vinted) — listings matching search criteria, plus observed
  price history and market stats

## Errors

See [Errors](/errors) for the `{ error, code? }` envelope and status codes.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.