REST API
The Luuphub REST API exposes everything the dashboard does — sites, boards,
posts, comments, votes, statuses, changelog, and cross-site insights — over stable,
versioned /v1 routes.
Interactive reference: the full request/response schemas render at /api-reference (Scalar), backed by the machine-readable OpenAPI 3.1 document. That spec is generated from the same Zod schemas the routes parse and return, so it can never drift from runtime.
Authentication
Send an API key as a bearer token:
GET /v1/sites HTTP/1.1
Host: app.luuphub.com
Authorization: Bearer lh_live_...
Create keys in the dashboard under Developers. API access requires a Pro plan
or higher; a key on a plan without API access gets a typed 402, never a silent
drop.
Scopes
Every key carries a set of scopes; a request missing the operation's scope gets a
403 naming the missing scope. New keys are read-only by default. A key may
also be restricted to one site — a request for another site is a 403 (IDOR
protection), never silently re-scoped.
sites:read— granted on a default read-only keyboards:read— granted on a default read-only keyboards:write— write scope, opt-inposts:read— granted on a default read-only keyposts:write— write scope, opt-incomments:read— granted on a default read-only keycomments:write— write scope, opt-invotes:write— write scope, opt-instatuses:read— granted on a default read-only keystatuses:write— write scope, opt-inchangelog:read— granted on a default read-only keysearch:read— granted on a default read-only keyinsights:read— granted on a default read-only keywebhooks:write— write scope, opt-inautomation:read— granted on a default read-only keyautomation:write— write scope, opt-in
Idempotency
Send an Idempotency-Key header on writes. A replay with the same key returns the
stored response (not a duplicate); the same key with a different body is a
422; a concurrent duplicate while the original is in flight is a 409.
Operations
| Method | Path | Summary | Scope |
|---|---|---|---|
GET |
/v1/sites |
List sites | sites:read |
GET |
/v1/sites/{siteId} |
Get a site | sites:read |
GET |
/v1/sites/{siteId}/boards |
List boards | boards:read |
POST |
/v1/sites/{siteId}/boards |
Create a board | boards:write |
GET |
/v1/sites/{siteId}/posts |
List posts | posts:read |
POST |
/v1/sites/{siteId}/posts |
Create a post | posts:write |
GET |
/v1/sites/{siteId}/posts/{postId} |
Get a post | posts:read |
PUT |
/v1/sites/{siteId}/posts/{postId}/status |
Change a post status | statuses:write |
POST |
/v1/sites/{siteId}/posts/{postId}/merge |
Merge a duplicate post into a survivor | posts:write |
GET |
/v1/sites/{siteId}/posts/{postId}/comments |
List a post comments | comments:read |
POST |
/v1/sites/{siteId}/posts/{postId}/comments |
Comment on a post | comments:write |
POST |
/v1/sites/{siteId}/posts/{postId}/votes |
Vote on a post | votes:write |
GET |
/v1/sites/{siteId}/statuses |
List statuses | statuses:read |
POST |
/v1/sites/{siteId}/statuses |
Create a status | statuses:write |
GET |
/v1/sites/{siteId}/changelog |
List changelog entries | changelog:read |
GET |
/v1/sites/{siteId}/search |
Search posts | search:read |
GET |
/v1/sites/{siteId}/insights |
Get a site AI-clustered feedback themes | insights:read |
GET |
/v1/automation/queue |
List the autopilot queue for a site | automation:read |
POST |
/v1/automation/runs |
Start an agent run | automation:write |
POST |
/v1/automation/runs/{runId}/steps |
Append a step to an agent run | automation:write |
POST |
/v1/automation/runs/{runId}/complete |
Complete an agent run | automation:write |
Errors & limits
- Typed JSON error bodies on
400/401/402/403/404/409/422/429. - Per-key rate limiting returns
429with retry guidance. - Cursor pagination on list endpoints (
limit1–100, opaquecursor).
Next
- Webhooks — get pushed the same events.
- MCP server — the API as agent tools.