HonestHook

RankingsSign in

Home · Docs · Endpoints · archive/trends

archive/trends — the history of a niche, grouped by item

Hourly readings the archive already recorded, replayed for any interval you ask for. The endpoint that answers questions about the past rather than about now.

This is archive data, and that is the point. A live platform API can tell you what is happening now. It cannot tell you what was happening last Tuesday, because it does not keep a record. We wrote down every hour, which is why this endpoint can answer a question about the past at all.

The call

PathGET /api/v1/trends/{niche}
Catalogue idarchive/trends
Cost1 credit per call. A call that finds nothing is charged all the same.
KeyRequired — Authorization: Bearer hk_live_...

Parameters (4)

NameInRequired
nichepathyes
fromqueryno
toqueryno
limitqueryno

That list is the whole list, and anything else is ignored in silence. An undeclared parameter is not rejected — it produces no error, no warning and no filtering. Check a parameter against this table before assuming a narrower result came back.

What the parameter list does not tell you

This is the endpoint that cannot be replicated by calling a platform API. Hacker News will tell you its front page right now; it will not tell you its front page on 18 September, because it does not keep one. We wrote down every hour, so the question 'what was happening then' has an answer here and nowhere upstream.

GROUPED BY ITEM, NOT BY WINDOW, and that shape is the whole design. A window is how the archive stores — one row per item per hour. An item carrying its own series is how the question gets asked: you want the trajectory of a thing, not a stack of unrelated snapshots. The regrouping happens in the database so you never have to stitch windows together yourself.

`movement` on each item is oldest position minus newest, and positive means it climbed. Read it together with `points` in the series, never alone: a change of position with no change in points is a tie reshuffle, not a trend, and ties are the rule rather than the exception in these rankings.

`left_at` is null while an item is still in the ranking. That null is not a missing value — it is the item not having left yet, which is a fact, and the reason the field is not an empty string or a zero date.

Measured caveats (3)

A nonexistent niche is not a 404 — and it spends the call

Nothing validates the niche name. A typo returns `items: []` with `points: 0` and HTTP 200, AND still spends a call, because the quota counter increments before the archive is read. An empty answer therefore means one of two different things — the niche is quiet, or the niche does not exist — and the response does not distinguish them. This is why step 1 of every recipe here resolves names at `/api/v1/nichos` first: that endpoint is free and needs no key, so the check costs nothing.

Source: The `/api/v1/trends/{niche}` description in the served `/openapi.json`.

An unknown parameter is ignored in silence

`/trends` declares exactly four inputs: `niche`, `from`, `to` and `limit`. Anything else is not rejected — it is ignored. A `?platform=hackernews` produces no error, no warning and no filtering: you get the unfiltered answer and nothing tells you the filter did not apply. Check the parameter against the list before assuming a narrower result.

Source: The declared parameter list in `lib/rotas-da-api.js` and the published `/openapi.json`.

The series is capped, and says when it was cut

`/trends` is capped at 5000 series points and a 90-day span, both enforced in the database. When a cap is hit, `truncated` is true and the series is incomplete — narrow the interval rather than drawing conclusions from a partial series. `limit` is a hint only: the hard cap lives in the database and a larger value does not raise it.

Source: The `/api/v1/trends/{niche}` description in the served `/openapi.json`.

Real responses

Captured, not composed. 1 response we could actually make from this machine:

$ curl "https://honesthook.com/api/v1/trends/ai-agents?hours=168"
{"error":"chave_ausente"}

HTTP 401
Real response, HTTP 401, captured for this page. The command as issued carries `hours`, which `/trends` does not declare — it is a `/movers` parameter. That is not what the 401 shows, though: the refusal happens before any parameter is read, so this transcript says nothing about how an unknown parameter is treated. The silent-discard warning below comes from the declared parameter list, not from this response.

Why there is no success body on this page

The 200 body for this endpoint is not transcribed here. Reading it needs a client key, and there is no client key on the machine these pages were built from — internal keys exist only as hashes, by design. An example we never received would look exactly like one we did, so instead of composing one, the response shape is documented field by field on the schema pages below. Those are generated from the contract and tested against it in both directions; an invented example would be tested by nothing.

Response shapes (3)

Error codes (8)

Every one of them carries the same body shape: ApiError. The error value is a stable string you can branch on — branch on that, never on the message text.

400 · 401 · 402 · 404 · 405 · 451 · 503 · 502

Machine-readable

This endpoint is in /openapi.json (OpenAPI 3.1), with its cost on the operation itself. If you are generating a client, use the spec rather than this page — and note that the spec is filtered by what is switched on right now, so it is the better answer to "can I call this today".

The other 6 endpoint pages

archive/movers · archive/coverage · profile/history · youtube/channel · pinterest/boards · bluesky/post

← All endpoint pages · Recipes · Schemas · Full docs