Webhooks let Surfer notify your server the moment something happens; like a Content Editor finishing processing or an Auto-Optimize run completing, so you don't have to poll for updates.
Webhook setup is handled by the Support Team. To get started:
Set up an HTTPS endpoint on your end that accepts POST requests and responds with HTTP 200 OK.
Contact Surfer Support via email or live chat and share the URL.
Support will register the endpoint and send you a Verification-Key to use for authenticating incoming requests on your end.
Once set up, Surfer will send a POST request to your endpoint whenever a supported event fires. Each request includes a Verification-Key header and a JSON body.
All webhook events follow the same envelope:
{
"id": 123,
"type": "event.name.here",
"timestamp": "2024-06-01T12:00:00Z",
"payload": {
...
}
}
Field | Type | Description |
| integer | Unique notification ID |
| string | Event name (see full list below) |
| string | ISO8601 UTC timestamp of when the event fired |
| object | Event-specific data (varies by event type) |
Fires after POST /api/v2/workspaces/{workspace_id}/content_editors completes processing.
Event | When it fires |
| Content Editor is ready to use |
| Processing failed |
Payload fields: draft_id (integer), permalink_hash (string)
{
"id": 123,
"type": "content_editor.initialization.completed",
"timestamp": "2024-06-01T12:00:00Z",
"payload": {
"draft_id": 5632898,
"permalink_hash": "kKi7n3pkRk7Gw5cxKDiBAbCAybnDTt2z"
}
}
Fires after you update the content inside a Content Editor via the API.
Event | When it fires |
| Score updated after a content change |
Payload fields: draft_id (integer), permalink_hash (string), content_score (integer)
{
"id": 124,
"type": "content_editor.content_score.recalculated",
"timestamp": "2024-06-01T12:05:00Z",
"payload": {
"draft_id": 5632898,
"permalink_hash": "kKi7n3pkRk7Gw5cxKDiBAbCAybnDTt2z",
"content_score": 74
}
}
Fires during and after Surfer AI article generation.
Event | When it fires |
| Full article finished generating |
| Outline is ready and waiting for review (only when |
| Generation failed |
Payload fields: draft_id (integer), permalink_hash (string)
Fires after an Auto-Optimize run completes, fails, or is cancelled.
Event | When it fires |
| Run finished |
| Run failed |
| Run was cancelled |
Payload fields: job_id (integer), draft_id (integer), result (string — only on completed)
The result field is either "optimized" (content was changed) or "nothing_to_optimize" (content was already well-optimized).
{
"id": 125,
"type": "content_editor.auto_optimize.completed",
"timestamp": "2024-06-01T12:10:00Z",
"payload": {
"job_id": 456,
"draft_id": 5632898,
"result": "optimized"
}
}
Event | When it fires |
| SEO score has been calculated |
| SEO score calculation failed |
Event | When it fires |
| AI Search score calculated |
| AI Search score calculation failed |
Event | When it fires |
| Outline generation finished |
| Outline generation failed |
Event | When it fires |
| Additional competitors loaded |
| Loading additional competitors failed |
Event | Applies to |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V1 + V2 |
| V2 only |
| V2 only |
| V2 only |
| V2 only |
| V2 only |
| V2 only |
| V2 only |
| V2 only |