Home · Docs · Recipes · Whether a spike held or decayed within six hours
Whether a spike held or decayed within six hours
Two reads of the same item six hours apart, compared on points — with the trap that makes position look like movement when nothing moved.
4 steps, using 3 endpoints. Step 1 is free and needs no key.
Read these first — they cost money if you do not
4 measured caveats apply to this recipe. They are worth more than the steps below: each one is a way the API answers plausibly while meaning something other than what you assumed.
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`.
`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`.
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`.
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.
The 4 steps
1. Resolve the niche name first — it is free, and skipping it costs
Nothing validates a niche name downstream, so a typo answers 200 with an empty list and still spends a call. This endpoint needs no key and costs no credits, so there is never a reason to guess. Take the `id` values from the response and use those verbatim.
$ curl -s "https://honesthook.com/api/v1/nichos"
{"niches":[{"id":"ai-agents","label":"AI agents","windows_24h":24,"last_window":"2026-10-02T09:00:00+00:00"},{"id":"devtools","label":"Developer tools","windows_24h":24,"last_window":"2026-10-02T09:00:00+00:00"},{"id":"indie-saas","label":"Indie SaaS","windows_24h":24,"last_window":"2026-10-02T09:00:00+00:00"}]}2. Ask /movers for a six-hour window
`hours=6` is a target, not a guarantee. The archive answers with the closest window it actually holds and reports the real gap, so a six-hour question can come back compared against a window four or nine hours old.
$ curl -H "Authorization: Bearer hk_live_..." \
"https://honesthook.com/api/v1/movers/indie-saas?hours=6"Watch for: If `interval_min` comes back as 320 you did not measure six hours, you measured five and a third. Decay per hour means `points_gained / (interval_min / 60)` — never divide by the 6 you sent.
3. Read the series, which is where decay is actually visible
`/movers` only ever reports items that GAINED between the two windows it compared — the schema says so. An item that spiked and then fell may not appear there at all, which means the endpoint that answers 'did it climb' cannot answer 'did it hold'. For that you need the hourly readings: each `SeriesPoint` carries `window`, `position`, `points` and `comments`, one per item per hour.
$ curl -H "Authorization: Bearer hk_live_..." \
"https://honesthook.com/api/v1/trends/indie-saas?from=2026-10-01T18:00:00Z&to=2026-10-02T06:00:00Z"Watch for: Compare `points` across consecutive `window` values on the same item. Points are monotonic upstream, so a spike that held shows a flat tail and one that decayed shows the rate of gain collapsing — the count itself does not fall.
4. Read `window`, not the order the points arrive in
`window` is rounded to the hour and is the bucket, not the exact capture time — two runs in the same hour share one. Captures are not equidistant, so the gap between consecutive points is not a constant hour. Read the timestamps; do not assume the spacing.
Watch for: This is the same mistake as dividing by the `hours` you asked for, one level down: a delta without its real interval is a number without a unit.
The shapes that come back
This recipe touches 4 response schemas. Each is documented field by field, generated from the contract and tested against it:
SeriesPoint— A single reading in an item's series: where it sat, how many points it had, how many comments. The archive keeps one of these per item per hour and never deletes them.Item— What `archive/trends` returns: an item, when it entered the ranking, when it left, its best position, and the full series of hourly readings behind it.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.
The endpoints used
What this page does not show you
The 200 bodies for the calls that need a key are not transcribed anywhere on this page, and that is deliberate rather than unfinished. Reading them needs a client key, there is no client key on the machine these pages were built from, and an example we never received would be indistinguishable from one we did — to you, and eventually to us. The field-by-field shape is on the schema pages above and is checked against the live contract by a test; an invented example would be checked by nothing.
The other 2 recipes
- Which topics in your niche climbed fastest this weekRank a week of archived history by how much each item actually gained, not by where it sits now. Three calls, one of them free.
- What was trending the day a competitor launchedPoint `from` and `to` at one past day and read back the ranking as the archive recorded it. This is the question no live API can answer.