> ## 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.

# Stack Overflow

> What a Nephia Watch on Stack Overflow captures, and what arrives in each event.

<Note>
  Stack Overflow needs a Stack Exchange key on the deployment — a **quota** question rather than an access one: an unauthenticated caller gets 300 requests a day, and a key (free, no OAuth flow) raises it to 10 000. On Nephia's hosted API it is configured; if you self-host, register at [stackapps.com](https://stackapps.com/apps/oauth/register) and set `STACKEXCHANGE_KEY`. `GET /account` reports which Sources a deployment offers in `capabilities.liveSources`.
</Note>

## The item

A Stack Overflow Watch emits a **StackItem**, and `type` says which kind it is: `question` or `answer`. Both ride one entity, exactly as Hacker News' items do — because on this Source the **answers are usually the news**. A product is asked about once and answered about ten times, and a Source that returned only questions would miss where the conversation is.

`title` is the **question's** title on both types. That is what the endpoint returns, and it is what places an answer for a reader.

`id` is kind-prefixed — `question-79998735`, `answer-79998810` — because the two share a numeric id space.

`score` is this item's own — an answer's score, not its question's. `questionScore` is the thread's, on both types.

`author` comes from a response filter Nephia asks for explicitly. The API's default filter on this endpoint returns no owner at all.

## Coverage

A Watch requires a **search term**. Tags narrow a search here but they do not *scope* one, so a Watch with no term would mean "every question on Stack Overflow".

| Criterion | Values                     | Default  |
| --------- | -------------------------- | -------- |
| `query`   | search text                | required |
| `tags`    | comma-separated, or a list | —        |

Tags are lowercased and ANDed: every result carries all of them. A reader writes `TypeScript, Node.js` and gets `typescript` + `node.js`.

**Stack Overflow only.** The other 180-odd Stack Exchange sites are one parameter away and are not covered yet.

**One term only.** The site's search ANDs every word it is given, so an `OR` would silently return nothing — the same behaviour Hacker News' and Bluesky's searches have. A quoted phrase *is* honoured, so `match: "word"` asks for it upstream.

### The index is not realtime

`/search/excerpts` reads an index that lags: a question can be asked a few minutes before it becomes searchable. That is a property of the Source, not a bug we can poll our way around, and it is why the five-minute floor is a floor rather than a promise of five-minute latency.

Nephia handles it rather than ignoring it: each tick narrows by the newest creation time it has seen **and** diffs against the ids it saw, so an item indexed late still arrives exactly once instead of being skipped by the time cutoff.

Interval: **300–86400** seconds. Cap: **20** active Watches per Account. Each tick costs **1 credit**.

The floor is arithmetic: twenty Watches at 300 s is 5 760 requests a day, under the 10 000 a key allows, with room for Explore runs on the same key. A two-minute floor would be 14 400 — over the ceiling, and the failure mode is a throttle for every user of the Source at once.

## What an event carries

The first tick establishes a silent baseline and emits nothing. Later ticks emit `stack_item.created`. `webhook_url` is optional — without it the Watch still records every match, readable through `GET /v1/stackoverflow/watches/{id}/events`. See [Webhooks](/webhooks).

```bash theme={null}
curl -X POST https://api.nephia.cc/v1/stackoverflow/watches \
  -H "x-api-key: $NEPHIA_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "query": "duckdb pivot",
    "tags": "sql, duckdb",
    "refresh_interval_seconds": 300,
    "webhook_url": "https://example.com/hooks/nephia"
  }'
```

A common shape — unanswered questions about your product — is a Watch plus one rule: `stackItem.type = question` and `stackItem.answers = 0`.

## Errors

A temporary Stack Exchange failure is **503** and is not charged; the Watch reports it in its activity, readable through `GET /v1/stackoverflow/watches/{id}/activity`. A throttle answers **429** and is not charged either.

A deployment with no `STACKEXCHANGE_KEY` answers **503** on these routes and omits `stackoverflow` from `capabilities.liveSources`.
