REST API
Developer documentation
Integrate SEOsoft into your CI pipeline, client reporting dashboard, or internal tooling. Every endpoint accepts JSON and returns JSON.
API access is included in the Command plan
Sign up or upgrade to get your API key and start building.
Overview
The SEOsoft API gives you programmatic access to your websites, reports, and account data. You can use it to trigger scans from a CI pipeline, pull results into your own dashboard, or automate monitoring for client sites. All endpoints return JSON and follow predictable REST conventions.
Base URL
https://api.seosoft.app/api/public/v1| Status | Meaning |
|---|---|
| 200 OK | Request succeeded |
| 201 Created | Resource created (POST /reports) |
| 204 No Content | Resource deleted successfully |
| 401 Unauthorized | Missing or invalid API key |
| 403 Forbidden | Your plan does not include this endpoint |
| 404 Not Found | Resource does not exist or belongs to another account |
| 422 Unprocessable Entity | Validation error — see errors field |
| 429 Too Many Requests | Rate limit exceeded — retry after X-RateLimit-Reset |
Authentication
All requests must include your API key as a Bearer token in the Authorization header. Keys are generated in Settings → API access and shown only once when created. Treat your key like a password — it grants full access to your account data.
curl https://api.seosoft.app/api/public/v1/account \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"Rate limits
Requests are limited to 60 per minute per API key. Every response includes rate limit headers so you can track your usage:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Total requests allowed per minute |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
| Retry-After | Seconds to wait before retrying (only on 429) |
Report creation (POST /reports) additionally counts against your plan's monthly scan quota — the same quota used when running scans from the dashboard. A 422 with quota_exceeded is returned when the monthly limit is reached.
Errors
All error responses use the same JSON envelope. The message field is always present. For 422 validation errors, the errors field maps field names to arrays of error strings.
// 401 Unauthorized
{
"message": "Unauthenticated."
}
// 422 Unprocessable Entity
{
"message": "The url field is required.",
"errors": {
"url": ["The url field is required."]
}
}
// 422 Quota exceeded
{
"message": "Monthly scan quota reached. Upgrade your plan to run more scans.",
"errors": {
"quota": ["quota_exceeded"]
}
}Account
https://api.seosoft.app/api/public/v1/accountGet account
Returns basic information about the authenticated account, including plan and identifiers.
Request
curl https://api.seosoft.app/api/public/v1/account \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"Response schema
| Field | Type | Description |
|---|---|---|
id | integer | Unique account ID |
name | string | Account display name |
email | string | Account email address |
plan | string | Current plan slug (e.g. command, growth, free) |
created_at | string (ISO 8601) | Account creation timestamp |
Response example
{
"data": {
"id": 42,
"name": "David Smith",
"email": "david@example.com",
"plan": "command",
"created_at": "2026-01-15T10:30:00Z"
}
}Websites
https://api.seosoft.app/api/public/v1/websitesList websites
Returns a paginated list of websites in your account, sorted by creation date by default.
Query parameters
| Parameter | Type | Description |
|---|---|---|
search | string | Filter by domain or label |
search_by | string | Field to search against. Default: domain |
sort_by | string | created_at · domain · score · report_count. Default: created_at |
sort | string | asc or desc. Default: desc |
per_page | integer | 10 · 25 · 50 · 100. Default: 10 |
page | integer | Page number. Default: 1 |
Request
curl "https://api.seosoft.app/api/public/v1/websites?per_page=25&sort_by=score&sort=asc" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"Response example
{
"data": [
{
"id": 1,
"domain": "example.com",
"score": 78,
"privacy": "public",
"report_count": 12,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-08-20T14:22:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 10,
"total": 47,
"last_page": 5
}
}https://api.seosoft.app/api/public/v1/websites/{id}Get website
Returns a single website by its ID.
Response schema
| Field | Type | Description |
|---|---|---|
id | integer | Website ID |
domain | string | Registered domain (e.g. example.com) |
score | integer | null | Latest aggregate score (0–100). Null if no reports yet |
privacy | string | public · private · password |
report_count | integer | Total number of reports for this website |
created_at | string (ISO 8601) | When the website was added |
updated_at | string (ISO 8601) | Last modification timestamp |
Request
curl https://api.seosoft.app/api/public/v1/websites/1 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"https://api.seosoft.app/api/public/v1/websites/{id}Update website
Updates a website's privacy setting. Only the fields you send are changed.
Body parameters
| Parameter | Type | Description |
|---|---|---|
privacy | integer | 0 = public · 1 = private · 2 = password-protected |
password | string | Required when privacy is 2. Min 4 characters. |
Request
curl -X PATCH https://api.seosoft.app/api/public/v1/websites/1 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"privacy": 1}'https://api.seosoft.app/api/public/v1/websites/{id}Delete website
Permanently deletes a website and all its associated reports. This cannot be undone. Returns 204 with no body on success.
Request
curl -X DELETE https://api.seosoft.app/api/public/v1/websites/1 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"Reports
https://api.seosoft.app/api/public/v1/reportsList reports
Returns a paginated list of reports across all your websites. Filter by website, result grade, or URL.
Query parameters
| Parameter | Type | Description |
|---|---|---|
website_id | integer | Filter to a specific website |
search | string | Filter by URL substring |
result | string | excellent · good · decent · poor — filter by grade |
sort_by | string | id · url · score · created_at. Default: created_at |
sort | string | asc or desc. Default: desc |
per_page | integer | 10 · 25 · 50 · 100. Default: 10 |
page | integer | Page number. Default: 1 |
Request
curl "https://api.seosoft.app/api/public/v1/reports?website_id=1&result=poor&per_page=25" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"Response example
{
"data": [
{
"id": 1,
"url": "https://example.com/blog/post",
"website_id": 1,
"score": 72,
"result": "decent",
"checks_total": 48,
"checks_passed": 35,
"checks_warned": 8,
"checks_failed": 5,
"created_at": "2026-08-01T10:30:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 10,
"total": 23,
"last_page": 3
}
}https://api.seosoft.app/api/public/v1/reports/{id}Get report
Returns a single report with full check-level detail. Use this to retrieve the complete results of a scan.
Response schema
| Field | Type | Description |
|---|---|---|
id | integer | Report ID |
url | string | The URL that was scanned |
website_id | integer | null | Associated website ID, if the URL belongs to a monitored website |
score | integer | null | Aggregate score (0–100) |
result | string | excellent · good · decent · poor — grade derived from score |
checks_total | integer | Total number of checks performed |
checks_passed | integer | Checks that passed |
checks_warned | integer | Checks with warnings |
checks_failed | integer | Checks that failed |
created_at | string (ISO 8601) | When the scan was run |
Request
curl https://api.seosoft.app/api/public/v1/reports/1 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"https://api.seosoft.app/api/public/v1/reportsCreate report
Triggers a full SEO scan of the given URL and returns the completed report. This is a synchronous operation — the response is returned once the scan finishes (typically 5–15 seconds). Report creation counts against your monthly scan quota.
Body parameters
| Parameter | Type | Description |
|---|---|---|
urlrequired | string | The full URL to scan, including https://. Must be publicly reachable. |
Request
curl -X POST https://api.seosoft.app/api/public/v1/reports \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/landing-page"}'Response example (201 Created)
{
"data": {
"id": 99,
"url": "https://example.com/landing-page",
"website_id": 1,
"score": 81,
"result": "good",
"checks_total": 48,
"checks_passed": 39,
"checks_warned": 6,
"checks_failed": 3,
"created_at": "2026-09-01T08:14:22Z"
}
}https://api.seosoft.app/api/public/v1/reports/{id}Delete report
Permanently deletes a report. Returns 204 with no body on success.
Request
curl -X DELETE https://api.seosoft.app/api/public/v1/reports/99 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
