Why a webhook?
Generating an SEO article (competitor analysis + writing + image synthesis) can take 2 to 4 minutes. Having the client hold the connection open and wait that whole time isn't practical — the request would time out. That's why SeoGeo kicks off generation asynchronously and, once the job finishes, sends the result to an address you specify. This mechanism is called a webhook.
The flow works like this:
- You specify your own endpoint via the
webhookUrlparameter in aPOST /v1/generaterequest. - SeoGeo immediately responds with
"status": "processing"and ajobId; the connection closes here. - When generation finishes in the background, SeoGeo sends a
POSTrequest to thewebhookUrlyou specified. - Your endpoint processes that request and returns
200 OK.
How do you set up the /v1/generate request?
The initial request is sent over HTTPS with an Authorization: Bearer YOUR_API_KEY header (requests over plain HTTP are rejected). The body fields are:
keyword(required) — the target keyword or topic.language(optional, default"tr") — the output language.includeImage(optional, defaulttrue) — whether to synthesize a cover image.webhookUrl(optional) — the address the result will bePOSTed to once generation completes.
{
"keyword": "2026 Electric Vehicle Trends",
"language": "en",
"wordCount": 1000,
"includeImage": true,
"webhookUrl": "https://api.yoursite.com/blog/import"
}
The response returned immediately (the article isn't ready yet — this only confirms the job was accepted) looks like this:
{
"status": "processing",
"jobId": "req_12345abc",
"message": "Article generation started."
}
What does the actual webhook payload look like?
Once generation completes, a POST request with a JSON body like the following arrives at your webhookUrl:
{
"id": "req_12345abc",
"status": "completed",
"article": {
"title": "2026 Electric Vehicle Trends",
"slug": "2026-electric-vehicle-trends",
"htmlContent": "<h1>2026 Electric Vehicle Trends</h1><p>...</p>",
"metaDescription": "2026 trends in the electric vehicle market...",
"imageUrl": "https://cdn.seogeo.com/.../image.jpg",
"tags": ["automotive", "technology"]
}
}
The key detail: the payload is nested under an article object, and the article body is in the htmlContent field — not plain text, but publish-ready HTML directly.
Building your own endpoint
You'll need to open a route in WordPress or your own CMS that accepts an incoming POST (for example, /api/blog/import). When building it:
- Add security verification. Verify a static token/secret value in the payload to confirm the request really came from SeoGeo; don't leave an unverified endpoint open.
- Remember to return
200 OK. Once you've successfully processed the request, you must return a200 OKresponse — otherwise the system may treat the request as failed. - Handle
id/slugidempotently. Design your endpoint so a second request with the sameid(in a retry scenario) doesn't create a duplicate post. - Save
htmlContentas-is. Since content already arrives as publish-ready HTML, there's no need to convert it to Markdown or any other format.
The practical approach for WordPress
On the WordPress side, the simplest path is to define a custom REST API route as your webhookUrl, then map the incoming article.title, article.slug, article.htmlContent, article.metaDescription, and article.imageUrl fields to the post title, slug, content, meta description (via your SEO plugin's relevant field), and featured image, respectively. The tags field can be assigned directly as WordPress tags.
Summary
A webhook integration has three parts: specifying webhookUrl in your /v1/generate request, opening an endpoint on your side that accepts the incoming POST to that address, and mapping the fields inside the article object to your CMS correctly while returning 200 OK. Because generation takes 2-4 minutes, this asynchronous flow is preferred over synchronous waiting.
