Companion thread API
Open a post's companion discussion thread with one authenticated call, from whatever tooling you already publish with. This is the automation behind "a comment section for your blog, without running a comment section": your blog stays your blog, and each post gets a discussion thread on Popsicle Boat that you can link to and pull replies from.
You don't need this API to use Popsicle Boat as your comments — you can create threads by hand in the web UI. This just removes the copy-paste for people who publish often.
1. Get set up (once)
-
Have an account and a space. Claim your space at popsicleboat.com/for-bloggers (or ask me, through the letters page, to set it up). A thread is a post in a space.
-
Mint a personal access token. Sign in, open your Settings page, and follow the API tokens link. Mint the token yourself — it is shown once, to you alone; only a hash is stored, so nobody (including me) can see it again. Store it where your publishing tool runs, e.g.
export POPSICLEBOAT_TOKEN=pbt_xxxxxxxxRevoke a token from the same page any time; tokens don't expire on their own.
2. Create a thread
POST https://www.popsicleboat.com/api/companion-threads
Authorization: Bearer <POPSICLEBOAT_TOKEN>
Content-Type: application/json
{
"space": "blogging",
"title": "Discuss: The page that rebuilds itself",
"body": "Companion thread for [my post](https://jva.lol/weblog/the-page-that-rebuilds-itself/).",
"source": "https://jva.lol/weblog/the-page-that-rebuilds-itself/"
}
| Field | Required | Notes |
|---|---|---|
space |
yes | The space's name, matched case-insensitively (the /c/<space> slug). |
title |
yes | The thread title. |
body |
yes | Markdown. Include a real link back to your post — that's the loop. |
source |
no | The blog post this thread discusses. Becomes the thread's source link: it drives the "Discussing a post on …" meta line, and in build-hook spaces the composer tells readers their replies show up on the post. Must be a public http(s) URL — a bad one fails the request. |
The thread is created as your user, public, in the named space.
Success — 201 Created
{
"url": "https://www.popsicleboat.com/c/blogging/posts/260",
"id": 260,
"space": "blogging"
}
Put url wherever your post records its discussion thread (for the Hugo
reference client, that's the post's popsicleboat: front-matter field).
Errors
| Status | error |
When |
|---|---|---|
401 |
unauthorized |
Missing or unknown Bearer token. |
404 |
space_not_found |
No approved space by that name — claim it first. |
422 |
missing_field |
space, title, or body was blank/absent. |
422 |
invalid |
The post was rejected (e.g. posting velocity, or a source that isn't a public http(s) URL). |
Every error body is { "error": "<code>", "message": "<human sentence>" }.
Example
curl -sS https://www.popsicleboat.com/api/companion-threads \
-H "Authorization: Bearer $POPSICLEBOAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"space":"blogging","title":"Discuss: my post","body":"Companion to [my post](https://example.com/my-post/)."}'
Security model
- Per-user, hashed. A token identifies one user. Only its SHA-256 hash is stored; the plaintext exists only in your hands.
- Scope. A token can do exactly what this endpoint does: create a public thread in an approved space, as you — the same thing you could do by hand in the web UI. It is not a session and grants no other access.
- Revoke. Revoke any token yourself from the same Settings page that minted it. Mint a fresh one anytime; they don't expire on their own.
- Treat it like a password. Keep it out of your repo and your build logs; pass it through an environment variable.
Reference client
The Hugo blog at jva.lol drives this with
scripts/companion-thread — it takes a post, calls this
endpoint, and writes the returned url into the post's popsicleboat: field,
so publishing a post with its thread is one command.