Skip to content

quickstart

Every example assumes you have an api key (see authentication) and jq for pretty output. Replace spk_<your_key> and the resource ids with values from your org.

The base url is https://api.spirby.com for production. On staging, swap in https://api-staging.spirby.com.

Terminal window
export SPIRBY_KEY="spk_<your_key>"
export SPIRBY_BASE="https://api.spirby.com"

The rest of the page uses these.

Terminal window
curl -s "$SPIRBY_BASE/v1/boards" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq

Returns { "data": [Board, ...], "nextCursor": "..." | null }. Default page size is 25, max 50. Pass ?cursor=...&limit=... for the next page.

Terminal window
curl -s -X POST "$SPIRBY_BASE/v1/boards" \
-H "Authorization: Bearer $SPIRBY_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Feedback","description":"What should we build?"}' | jq

Returns 201 with { "data": Board } and a Location: /api/v1/boards/<id> header. Slug is derived from the name unless you pass one.

Terminal window
curl -s "$SPIRBY_BASE/v1/boards/$BOARD_ID" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq
Terminal window
curl -s "$SPIRBY_BASE/v1/boards/$BOARD_ID/posts?status=open&sort=most_voted&limit=10" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq

Filters: status (single or repeated), tagIds (match-any), query (full-text), sort (most_voted | newest | recently_active | relevance). relevance falls back to most_voted when no query is set. Pagination via cursor + limit (max 50).

Terminal window
curl -s -X POST "$SPIRBY_BASE/v1/boards/$BOARD_ID/posts" \
-H "Authorization: Bearer $SPIRBY_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Add csv export",
"body": { "json": null, "text": "We need to download the post list as a spreadsheet." }
}' | jq

Returns 201 with the new post. The author is whichever user minted the api key.

6. read a post (with tags + merge metadata)

Section titled “6. read a post (with tags + merge metadata)”
Terminal window
curl -s "$SPIRBY_BASE/v1/posts/$POST_ID" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq

The response includes tags, mergedIntoSlug (if this post was merged into another), and shippedInEntry (if a changelog entry references it).

Terminal window
curl -s -X PATCH "$SPIRBY_BASE/v1/posts/$POST_ID" \
-H "Authorization: Bearer $SPIRBY_KEY" \
-H "Content-Type: application/json" \
-d '{"status":"in_progress"}' | jq

A status change enqueues a notification job for subscribers; the api response does not wait on the queue. Requires read:write scope.

Terminal window
curl -s -X POST "$SPIRBY_BASE/v1/posts/$POST_ID/votes" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq

Returns { "data": { "voted": true, "voteCount": <int> } }. Calling it again with the same key is a no-op — the response shape is identical.

To retract: curl -X DELETE "$SPIRBY_BASE/v1/posts/$POST_ID/votes" -H "Authorization: Bearer $SPIRBY_KEY".

Terminal window
curl -s -X POST "$SPIRBY_BASE/v1/posts/$POST_ID/comments" \
-H "Authorization: Bearer $SPIRBY_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": { "json": null, "text": "Sounds great. Counting on this for q2." }
}' | jq

Pass parentId for one-level replies. Comments are rate-limited per ip (30/h) and per user (60/h) — these limits are separate from the per-key budget.

10. publish a changelog entry (action endpoint)

Section titled “10. publish a changelog entry (action endpoint)”
Terminal window
curl -s -X POST "$SPIRBY_BASE/v1/changelog/$ENTRY_ID/publish" \
-H "Authorization: Bearer $SPIRBY_KEY" | jq

The entry must already exist (POST /v1/boards/{boardId}/changelog). Publishing flips status to published, sets publishedAt = now, and enqueues a subscriber broadcast. The endpoint is idempotent — replaying it on an already-published entry is a no-op.

  • want the rest of the surface? see /api/reference — the browseable spec — or grab openapi.json.
  • shipping a webhook receiver? jump to webhooks for payload shapes and signature verification.