Home · API
API documentation
Every other social data API answers what is trending now. This one answers what was trending, and where it is going — which nobody can reconstruct later, because the past was not photographed.
Get a key
Free while the archive is young: 1,000 calls a month, no card, no sales call. The quota renews on the 1st.
Prefer the terminal? The signup is an endpoint too — no browser required:
curl -X POST https://honesthook.com/api/v1/chaves \
-H "Content-Type: application/json" \
-d '{"email":"you@company.com"}'The key is returned once and never again: the database stores only its SHA-256. If you lose it, write to kauvpereira@gmail.com and we rotate it by hand. Automatic re-issue would let anyone knock out your key by typing your address.
Authentication
Send the key as a bearer token. Every request to the archive needs it; discovery does not.
curl https://honesthook.com/api/v1/trends/ai-agents \
-H "Authorization: Bearer hk_live_..."Endpoints
GET /api/v1/nichos — what exists, and since when
No key required. Returns the niches and how much history each one has — never a line of the archive itself. Today: AI agents, Developer tools, Indie SaaS.
GET /api/v1/trends/{nicho} — the archive
Key required. Returns the history of one niche grouped by item, not by window. A window is how the archive stores; an item with a series is how the question gets asked.
| Parameter | Meaning |
|---|---|
desde | ISO 8601. Defaults to 7 days ago. Capped at 90 days back. |
ate | ISO 8601. Defaults to now. |
limite | A hint. The hard cap is 5,000 series points and lives in the database — a larger number here does not raise it. |
POST /api/v1/chaves — issue a key
Takes {"email": "..."}, returns 201 with the key in plain text, once. One active key per address; a second request returns 409, without echoing anything about the key that already exists.
What comes back
{
"nicho": "ai-agents",
"desde": "2026-08-30T00:00:00Z",
"ate": "2026-09-06T16:00:00Z",
"pontos": 412,
"truncado": false,
"cota_usada": 3,
"cota_limite": 1000,
"itens": [
{
"item_externo_id": "44912730",
"titulo": "...",
"url": "https://...",
"plataforma": "hackernews",
"entrou_em": "2026-09-05T14:00:00Z",
"saiu_em": "2026-09-06T15:00:00Z",
"melhor_posicao": 3,
"movimento": 9,
"serie": [
{ "janela": "2026-09-05T14:00:00Z", "posicao": 12, "pontos": 41 },
{ "janela": "2026-09-05T15:00:00Z", "posicao": 3, "pontos": 96 }
]
}
]
}movimento is the oldest position minus the newest: positive means it climbed. truncado being true means you hit the 5,000-point cap and the series is incomplete — narrow the interval instead of drawing conclusions from a partial one.
Errors
Every failure carries a stable erro code. Branch on the code, not on the prose.
| HTTP | erro | Meaning |
|---|---|---|
| 400 | intervalo_invalido | desde or ate is not ISO 8601. |
| 400 | email_invalido | Signup only. |
| 401 | chave_ausente | No Authorization header. |
| 401 | chave_invalida | Unknown or deactivated key. |
| 404 | nicho_invalido | No such niche. List them at /api/v1/nichos. |
| 405 | metodo_invalido | The archive is GET; signup is POST. |
| 409 | ja_tem_chave | That address already has an active key. |
| 429 | cota_estourada | Body carries limite and renova_em. |
| 502 | indisponivel | Ours, not yours. Retry. |
Successful reads also carry X-RateLimit-Limit and X-RateLimit-Remaining, so you can watch the quota without spending a second call on it.
Limits
| Limit | Value | Enforced where |
|---|---|---|
| Calls | 1,000 / month, renewing on the 1st | Database |
| Span per call | 90 days | Database |
| Series points per call | 5,000 | Database |
| Keys per email | 1 active | Unique index |
All four are enforced inside Postgres, not in the HTTP layer. That is deliberate: the browser-side database key is public, so a limit living in the route would be a limit anyone could walk around.
What this data does not support yet
A trend archive that flatters itself is worthless, so here is the part most API docs leave out.
Position is weaker than points, and before 2026-09-06 15:20 UTC it is unreliable. Until that moment the ranking was ordered by score alone, and tied items landed in whatever order the upstream search returned — which varies between calls. Most items in a snapshot sit within three points of each other, so ties are the rule, not the exception. In one measured pair of windows, 19 of 29 items “changed position” without gaining or losing a single point. Ordering is deterministic from that timestamp on. For anything earlier, read pontos and treat posicao as decoration.
A window is rounded to the hour, and that erases the real interval. Two captures 12 minutes apart and two captures 96 minutes apart both look like “one window”. The rounding is what makes collection idempotent and it is staying — but a delta without an interval is a number without a unit, so read the timestamps in serie rather than assuming an hour passed.
One source is live today: Hacker News. Reddit is written and waiting on credentials. This matters unevenly by niche — Hacker News barely discusses indie SaaS, so that niche is thin by coverage, not by frequency. Check the status page before building on a niche: it publishes the last capture and the last 24 hours per source, including the sources that are broken.
We archive aggregate trend, never people. No author, no body text, no profile, no photo — only title, metric and position. That is enough to answer where a topic is going, and it keeps the archive out of the personal-data question entirely. See privacy.
Machine-readable
The full spec is at /api/v1/openapi.json (OpenAPI 3.1), and there is an /llms.txt for agents. If you are pointing a model at this API, hand it the spec rather than this page.
Questions the archive can already answer
Which topics in your niche climbed fastest this week; what was trending the day a competitor launched; whether a spike held or decayed within six hours.
← Back to the front page · Archive status · kauvpereira@gmail.com