Overview
The Seobox API lets you list connected sites, read generated articles, and trigger new content generation from your own systems — useful for agencies syncing multiple client accounts, or for triggering generation from an internal tool instead of the dashboard.
All endpoints are served from:
https://api.seobox.tech/v1
Every request must include your API key and, for workspace-scoped endpoints, the target workspace:
x-api-key: sk_live_your_key_here
x-workspace-id: wsp_abc123
read and/or write scopes — request only what you need.
Authentication
Pass your API key on every request via the x-api-key header. Keys are scoped to read, write, or both — a read-only key can list sites and blogs but will be rejected on /generate. Missing or invalid keys return 401 Unauthorized; a valid key without the required scope returns 403 Forbidden.
Endpoints scoped to a specific workspace (most of them) additionally require an x-workspace-id header identifying which workspace within your account to operate on. Omitting it on a workspace-scoped endpoint returns a 400 Bad Request with a message telling you which header is missing.
Endpoints
GET /v1/api/sites
Lists every active site connected to your account.
Scope required: read
curl https://api.seobox.tech/v1/api/sites \
-H "x-api-key: sk_live_your_key_here"
{
"success": true,
"data": [
{
"uid": "site_9f2a...",
"domain": "example.com",
"name": "Example Co Blog",
"cms_type": "wordpress",
"gsc_connected": true,
"status": "active"
}
]
}
GET /v1/api/blogs
Lists generated articles for a site, scoped to a workspace. Supports cursor-based pagination.
Scope required: read · Requires: x-workspace-id
curl "https://api.seobox.tech/v1/api/blogs?limit=20" \
-H "x-api-key: sk_live_your_key_here" \
-H "x-workspace-id: wsp_abc123"
{
"success": true,
"data": [
{
"uid": "blog_7c1e...",
"title": "Keyword Research That Finds Intent, Not Just Volume",
"slug": "keyword-research-that-finds-intent",
"status": "published",
"target_keyword": "keyword research",
"seo_score": 91,
"published_url": "https://example.com/blog/keyword-research-that-finds-intent",
"published_at": "2026-07-05T09:12:00.000Z"
}
],
"next_cursor": "blog_5a2d..."
}
Pass the returned next_cursor back as a cursor query parameter to fetch the next page.
GET /v1/api/blogs/:uid
Fetches a single generated article by its unique ID.
Scope required: read · Requires: x-workspace-id
curl https://api.seobox.tech/v1/api/blogs/blog_7c1e... \
-H "x-api-key: sk_live_your_key_here" \
-H "x-workspace-id: wsp_abc123"
Returns 404 Not Found if the article doesn't exist, or doesn't belong to the account/workspace identified by your key and header.
POST /v1/api/generate
Queues a new article for generation against a target keyword.
Scope required: write · Requires: x-workspace-id
curl -X POST https://api.seobox.tech/v1/api/generate \
-H "x-api-key: sk_live_your_key_here" \
-H "x-workspace-id: wsp_abc123" \
-H "Content-Type: application/json" \
-d '{
"site_uid": "site_9f2a...",
"keyword": "b2b saas seo",
"secondary_keywords": ["saas content marketing"],
"tone": "expert, direct"
}'
| Field | Type | Required | Notes |
|---|---|---|---|
site_uid |
string | Yes | Must reference an active site in the workspace |
keyword |
string | Yes | 2–200 characters |
secondary_keywords |
string[] | No | Up to 10 supporting keywords |
tone |
string | No | Freeform tone guidance passed to the writer |
This returns immediately with 202 Accepted — generation runs asynchronously:
{
"success": true,
"run_id": "run_3e9b...",
"blog_uid": "blog_1a4f..."
}
Poll GET /v1/api/blogs/:uid with the returned blog_uid to check status, or subscribe to the generation.completed webhook event to be notified the moment it's ready instead of polling.
Errors
All errors follow the same shape:
{
"success": false,
"error": { "message": "Site not found" }
}
| Status | Meaning |
|---|---|
400 |
Malformed request or missing required header/field |
401 |
Missing or invalid API key |
403 |
Valid key, insufficient scope |
404 |
Resource not found, or not owned by your account/workspace |
429 |
Rate limit exceeded |
Rate limits
API requests are rate-limited per key. If you're bursting past your limit, requests return 429 Too Many Requests with a Retry-After header — back off and retry rather than hammering the endpoint, especially for /generate, which is the most expensive call in the API.
FAQ
Can I revoke an API key without affecting others? Yes, keys are generated individually per account from Account Settings and can be rotated or revoked independently.
Is there a sandbox/test environment?
Use a read-scoped key against /sites and /blogs to integrate safely before granting write scope for /generate in production.
How do I know when a generated article is done?
Either poll GET /v1/api/blogs/:uid for a published status, or register a webhook for generation.completed — see Webhooks.
