Event Webhooks
Event webhooks tell your systems when something happens to your articles — for example, to post a Slack message when an article is ready for review.
This is different from the Custom Site webhook, which delivers the article itself to your website for publishing. Event webhooks only carry notifications.
Setting up
Go to Settings → API → Webhooks, enter your endpoint URL, and click Save. SEObox shows a
signing secret starting with whsec_ once — store it on your server. To stop deliveries,
click Remove.
One URL per account receives every event.
Request
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: SEOBOX-Webhooks/1.0
X-SEOBOX-Signature: <hex HMAC-SHA256 of the raw body, keyed with your whsec_ secret>{
"event": "blog.published",
"account_id": "66f1c2a9e4b0a1b2c3d4e5f5",
"data": {
"blog_id": "66f1d0b2e4b0a1b2c3d4e600",
"blog_uid": "9a7c2e4f-1b3d-4c5e-8f6a-2b4d6e8f0a1c",
"title": "How to Choose a Standing Desk in 2026",
"published_url": "https://example.com/blog/how-to-choose-a-standing-desk",
"cms_post_id": "812"
},
"timestamp": "2026-09-18T10:42:11.000Z"
}There’s no event header. Read the event name from the event field in the body. Verify the
signature exactly as shown in the
Custom Site guide, using your whsec_ secret.
Events
| Event | When | data fields |
|---|---|---|
blog.ready_for_review | An article finished generating | blog_id, blog_uid, title, target_keyword, seo_score, geo_score |
blog.published | An article went live on your site | blog_id, blog_uid, title, published_url, cms_post_id |
blog.failed | Article generation failed | blog_id, blog_uid, target_keyword, error |
blog.blocked_quality | An article didn’t pass quality checks | blog_id, blog_uid, target_keyword, failed_checks, scores (word_count, seo_score, geo_score, aeo_score) |
Publishing failures don’t send an event. They’re shown on the article in the dashboard.
Delivery and retries
- Respond with any 2xx within 15 seconds.
- A 4xx response is treated as final and isn’t retried.
- A 5xx, a network error, or a timeout is retried up to 3 more times, after 1, 2, and 4 seconds. After that the event is dropped.
- The URL must be publicly reachable; private and internal addresses aren’t delivered to.