HonestHook

RankingsSign in

Tutorials

Hacker News search in Python

One authenticated call to /api/v1/hackernews/search?q=rust&limit=25, the response it returned, and the line that reads one field out of it.

What you need

Standard library only — urllib and json ship with Python 3. There is nothing to pip install.

The call

import json
import os
import urllib.request

url = "https://honesthook.com/api/v1/hackernews/search?q=rust&limit=25"

request = urllib.request.Request(
    url,
    headers={"Authorization": "Bearer " + os.environ["HH_KEY"]},
)

with urllib.request.urlopen(request, timeout=30) as response:
    envelope = json.load(response)

print(envelope["success"], envelope["platform"], envelope["endpoint"])

What came back

{
  "success": true,
  "platform": "hackernews",
  "endpoint": "hackernews/search",
  "data": {
    "author": {
      "id": null,
      "handle": null,
      "followers": null
    },
    "items": [
      {
        "id": "46990729",
        "title": "An AI agent published a hit piece on me",
        "url": "https://news.ycombinator.com/item?id=46990729",
        "published_at": "2026-09-28T11:04:22.000Z",
        "metrics": { "points": 412, "comments": 176 },
        "position": 1
      }
    ],
    "has_more": null
  },
  "error": null,
  "cached": false
}

Recorded response, captured 30 Sep 2026. A live call returns the value at the moment you ask, not this one.

Every field in that capture

In PythonType in this capture
envelope["success"]boolean
envelope["platform"]string
envelope["endpoint"]string
envelope["data"]["author"]["id"]null
envelope["data"]["author"]["handle"]null
envelope["data"]["author"]["followers"]null
envelope["data"]["items"]array (1 in this capture)
envelope["data"]["has_more"]null
envelope["error"]null
envelope["cached"]boolean

A field we cannot read comes back null, never 0. A zero would be a claim about the account; null is a fact about our collection. The full list of what this route does not return is on hackernews-api/search.

Reading one field

print(envelope["data"]["items"])

envelope is the dict from the block above. os.environ raises if the key is not set, which is better than sending the word None as a bearer token.

Every other tutorial here reads somebody's profile. This one does not, and the difference shows up in the response: there is no account to describe, so the author fields are null and the thing you want is items.

Hacker News has no follow graph. There is no follower count to return, and no profile endpoint either — that absence is a decision, not a gap.

What you are calling

One authenticated GET to our endpoint, with your key in an Authorization header. Behind it is the public Algolia index of Hacker News. The query in the example is the one that produced the recorded response below.

Each item carries its title, its link, when it was posted, and its points and comment count. The response shows one item; a real call returns the page you asked for.

Two things about the index

It does not understand OR. A query written as a boolean expression is read as words, so you get results for the words — not an error telling you the operator was ignored.

And typo tolerance is on by default, which means a short query can return a page of results that have nothing to do with what you typed while looking like a perfectly successful search. Check that the titles are about your subject before you count anything.

Before you copy the block

Keep the key in an environment variable — all three examples read HH_KEY.

The endpoint itself

Parameters, the handle format, what the route does not return and what a call costs: hackernews-api/search.

The same call in curl · JavaScript.

Free key, 1,000 credits a month

Every example above runs against the real endpoint as soon as you have a key. No card, and the key arrives in seconds.

Get a key →

← Tutorials · hackernews-api · Pricing