Home · Docs · Endpoints · archive/movers
archive/movers — what gained traction, ranked by the gain
Compares two archived windows and ranks by points gained, not by position. Charged only when it finds movement.
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
| Path | GET /api/v1/movers/{niche} |
|---|---|
| Catalogue id | archive/movers |
| Cost | 10 credits per call. A call that finds nothing costs nothing. |
| Key | Required — Authorization: Bearer hk_live_... |
Parameters (3)
| Name | In | Required |
|---|---|---|
niche | path | yes |
hours | query | no |
limit | query | no |
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
The question here is what ACCELERATED, which is a different question from what is big. A post sitting at position 3 for two days is large and static; a post that went from 40 points to 180 in six hours is the one worth knowing about, and it may still be below the first one in the ranking. This endpoint sorts by the second thing.
RANKED BY `points_gained`, AND THE REASON IS MEASURED. Across 19 pairs of windows on 2026-09-06, position changed for 19 of 29 items without a single point changing. Most items in a snapshot sit within a few points of each other, so ties dominate, and a tie reshuffle is indistinguishable from real movement if you read `position`. `points_gained` is the upstream counter, not a number we derive — so it moves only when something actually happened.
`position` comes back anyway, for reference, so you can see where an item sits now. Do not rank by it and do not diff it across calls. The schema page says the same thing in the field note, because this is the single most expensive misreading available here.
IT ONLY EVER REPORTS GAINS. An item that spiked and then decayed is not in this response — `points_gained` is always positive. If your question is whether something HELD, this endpoint cannot answer it and `archive/trends` can, by giving you the hourly series. The two are not interchangeable and the recipes keep them apart.
An empty answer is a success, not an error, and it is not charged. A quiet window returns HTTP 200 with `credits_charged: 0` and a `note` saying so. The risk of calling into a quiet window sits with us by design — you should not need defensive logic to decide whether it is worth asking.
Measured caveats (5)
Position changes without points changing
Measured on 2026-09-06 across 19 pairs of windows: position changed for 19 of 29 items WITHOUT A SINGLE POINT CHANGING. Most items in a snapshot sit within a few points of each other, so ties are the rule and a tie reshuffle looks exactly like movement if you read `position`. That is why `/movers` ranks by `points_gained` — an upstream counter — and carries `position` for reference only.
Source: The `/api/v1/movers/{niche}` description in the served `/openapi.json`.
`interval_min` is the real gap, not the one you asked for
`/movers` compares the newest window against the archived window whose real capture time is closest to `hours` ago. Windows are not equidistant — observed gaps have ranged from 12 to 321 minutes — so asking `hours=24` against an archive 20 hours deep answers `interval_min: 1208`, not 1440. Divide `points_gained` by `interval_min`, never by the number you sent.
Source: The `/api/v1/movers/{niche}` description in the served `/openapi.json`.
The ranges /movers enforces
`hours` accepts 1 to 720 and defaults to 24. `limit` accepts 1 to 100 and defaults to 20. Out of range is an explicit 400, never silently clamped on the way in — but `limit` IS clamped to 100 inside the database, so a larger value does not raise the cap.
Source: The `/api/v1/movers/{niche}` parameter schemas in the served `/openapi.json`, transcribed 2 Oct 2026.
An empty /movers result is a 200 and is not charged
`/movers` charges only if it finds movement. A quiet window answers HTTP 200 with `credits_charged: 0`, `items: []` and a `note` saying so — not an error and not a charge. The risk of an empty window sits with us, so you do not need defensive logic to avoid calling. Branch on `total`, not on the status code.
Source: The `/api/v1/movers/{niche}` description in the served `/openapi.json`, and `cobra_sem_resultado` on its catalogue row.
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`.
Real responses
Captured, not composed. 1 response we could actually make from this machine:
$ curl "https://honesthook.com/api/v1/movers/ai-agents"
{"error":"chave_invalida","http":401}
HTTP 401Why 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 (2)
Mover— What `archive/movers` returns. The ranking key is `points_gained`, not `points` and not `position` — the question is what accelerated, not what is big.ApiError— Every 4xx and 5xx from the API carries this object. The `error` value is a stable string you can branch on; the extra fields appear only for the errors that have something to report.
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/trends · archive/coverage · profile/history · youtube/channel · pinterest/boards · bluesky/post