Documentation
Publishing API Reference
Payload contracts and expected response semantics for PrismSEO publishing workflows.
Publishing API Reference
This is the exact contract PrismSEO uses when publishing to a custom webhook destination. If you're integrating a Next.js app, a headless CMS, or an internal pipeline, this page is the source of truth. For a step-by-step walkthrough, see the Webhook Integration guide.
Request
PrismSEO sends a single HTTPS POST to your configured URL.
POST <your-webhook-url> HTTP/1.1
Content-Type: application/json
Authorization: Bearer <your-webhook-token>
User-Agent: PrismSEO-Webhook/1.0
- Method — always
POST. - Auth —
Authorization: Bearer <token>, where the token is the value you set on the connection. Validate it on every request. - Timeout — PrismSEO aborts after 15 seconds. Respond before then.
- Transport — HTTPS only. Private, localhost, and non-HTTPS URLs are rejected.
Event envelope
{
"event": "article.published",
"integration_name": "My Production Site",
"article": { }
}
event— one of:
- article.published — published live (mode = publish)
- article.drafted — published as a draft (mode = draft)
- test — a manual test event from the dashboard
integration_name— the connection's label.article— the article object below.
Article object
id*(string)* — stable UUID. Use as the idempotency key.title*(string)* — display title / H1.slug*(string)* — URL-safe, de-duplicated slug.content_html*(string)* — full article body as HTML.excerpt*(string)* — short summary (falls back to meta description).meta_title*(string)* — SEO title tag.meta_description*(string)* — meta description.published_at*(string)* — ISO 8601 timestamp of the event.prism_css*(string, optional)* — CSS to stylecontent_html. Inject once per page if you don't already style article HTML.
Response semantics
Your endpoint's HTTP status decides how PrismSEO records the publish:
2xx— accepted. Recorded aspublishedin Publish History.4xx— validation or auth problem on the payload/config. Recorded asfailed; not retried (fix the request).5xx— your destination failed transiently. Recorded asfailed; safe to retry because the payload was valid.
Response bodies are logged for debugging, so return a short JSON message on errors.
Reference receivers
Next.js (App Router)
// app/api/prismseo-webhook/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) {
if (req.headers.get('authorization') !== `Bearer ${process.env.PRISMSEO_WEBHOOK_TOKEN}`) {
return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
}
const { event, article } = await req.json()
if (!article?.id || !article?.content_html) {
return NextResponse.json({ error: 'invalid payload' }, { status: 400 })
}
await savePost(article, event === 'article.published' ? 'published' : 'draft')
return NextResponse.json({ ok: true })
}
Node / Express
import express from 'express'
const app = express()
app.use(express.json({ limit: '2mb' }))
app.post('/prismseo-webhook', async (req, res) => {
if (req.get('authorization') !== `Bearer ${process.env.PRISMSEO_WEBHOOK_TOKEN}`) {
return res.status(401).json({ error: 'unauthorized' })
}
const { event, article } = req.body
if (!article?.id || !article?.content_html) {
return res.status(400).json({ error: 'invalid payload' })
}
await savePost(article, event === 'article.published' ? 'published' : 'draft')
res.json({ ok: true })
})
Reliability recommendations
- Treat
article.idas the idempotency key — upsert, never insert blindly. - Persist the payload before any processing, so a downstream failure never loses the article.
- Respond fast (under 15s); run deploys, image handling, and re-indexing after you reply.
- Log the response body on non-2xx so repeated failures are debuggable from Publish History.
Next step
Apply this setup, then run your first publish cycle from your dashboard.