Everything you need to drive Polyblog from your own code: a REST API with scoped keys, endpoints for articles, blogs and topics, and signed webhooks for every change.
API keys
The Polyblog REST API is what you use to publish from a CMS, a static site generator, a CI pipeline or any backend of your own. Every request is authenticated with an API key you create yourself.
Send the secret as HTTP Basic credentials. All endpoints are relative to https://api.polyblog.io.
Authorization: Basic base64(<your key secret>)A key pinned to a blog can only ever touch that blog, and a key can only ever touch the organization it was created in — the tenant is read from the key, never from the request.
Quick start
List the articles of a blog. Anonymous callers only ever see published articles; with a key of the owning organization you also get drafts.
curl "https://api.polyblog.io/api/articles?blogId=YOUR_BLOG_ID&locale=en" \
-H "Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)"Posting an article publishes it on your blog and fires the article.created webhook.
curl -X POST "https://api.polyblog.io/api/articles" \
-H "Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)" \
-H "Content-Type: application/json" \
-d '{
"blogId": "YOUR_BLOG_ID",
"locale": "en",
"title": "Hello from the API",
"description": "A short summary used in listings and meta tags.",
"content": "<p>Written straight from my own backend.</p>",
"published": true
}'Browse the full API reference — every endpoint with its parameters, request body, responses and required scope.
Scopes
Each key carries a set of per-resource scopes, so an integration that only needs to read articles cannot delete them. New keys start read-only; widen them explicitly.
A request made with a key that lacks the required scope is refused with 403. Keys are also rate limited, and a request over the limit is refused with 429.
Webhooks
Subscribe an endpoint of yours and Polyblog POSTs each matching event to it as it happens. A subscription can cover the whole organization or a single blog, and can filter the events it wants.
POST https://your-server.com/polyblog-webhook
X-Polyblog-Event: article.created
X-Polyblog-Signature: t=1719000000,v1=<hmac-sha256 hex>
Content-Type: application/json
{
"event": "article.created",
"timestamp": 1719000000,
"data": { "...": "..." }
}Every delivery carries an X-Polyblog-Signature header of the form t=timestamp,v1=signature. The signature is an HMAC-SHA256 of timestamp.body keyed by your subscription secret; recompute it over the raw body and compare before trusting the payload.
import crypto from 'node:crypto'
// body must be the RAW request body, byte for byte
function isSignatureValid({ header, body, secret }) {
const [t, v1] = header.split(',')
const timestamp = t.slice(2)
const signature = v1.slice(3)
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
)
}Delivery is one best-effort attempt with a 5 second timeout and no retries. Failures are counted, and a subscription that fails 20 times in a row is deactivated until you re-enable it.
Subscriptions are managed from your dashboard or through the webhook subscriptions endpoints in the API reference.
Start building