API Reference
PerSeo Insights REST API v1.0
Base URL
https://insights.perseodesign.com/api/v1
The PerSeo Insights REST API lets you start SEO scans, read results, export reports and manage access tokens programmatically. Ideal for CI/CD, automated monitoring and third-party tool integrations. v1.0.0 adds readability scores, keyword analysis, bulk scan (up to 50 URLs), webhook callbacks and HTTPS/HTTP auto-fallback.
To create your first API key, go to the Dashboard, section API & Token.
Authentication
All endpoints require a Bearer token in the HTTP header:
API Key (permanent)
Long-lived tokens created from the Dashboard. They start with sk_live_. Use them for scripts, automations and server-side integrations.
JWT (session 24h)
Short-lived tokens (24h) issued by POST /auth/login. Use them for interactive clients requiring explicit login.
Available scopes
| Scope | Description |
|---|---|
| read | Read access: profile, history, token list |
| scan | Start new scans (POST /scans) |
| export | Export results (GET /scans/{id}/export/{format}) |
Rate limits
API limits mirror the website limits. Reset every 24h (sliding window).
| Tier | Single Scan/day | Sitemap Scan/day | Crawl/day | Scheduled Reports |
|---|---|---|---|---|
| Guest (unauthenticated) | 1 | 1 | - | - |
| Free (registered) | 5 | 5 | 1 | 1 |
| Pro | 50 | 10 | 10 | 10 |
For more details on plans and features, visit the Pricing page.
Response format
All responses follow the standard JSON format:
Success
Error
Auth
/api/v1/auth/login
No auth
Authenticate with email/password and receive a JWT access token (24h).
Response 200
/api/v1/auth/verify
JWT Bearer
Verifies the validity of a JWT token.
API tokens
/api/v1/tokens
scope: read
Lists all API keys for the authenticated user.
/api/v1/tokens
scope: read
Creates a new API key. The token is shown only once.
| Field | Type | Req. | Description |
|---|---|---|---|
| name | string | SI | Token label (max 100 chars) |
| scopes | array | NO | Default ["read"]. Values: read, scan, export |
token field in the response is shown only once. Save it immediately in a secure place.
/api/v1/tokens/{id}
scope: read
Permanently revokes (disables) an API key.
Scans
/api/v1/scans
scope: scan
Starts an asynchronous SEO scan. Returns 202 Accepted and a scan_id to use for polling.
| Field | Type | Req. | Description |
|---|---|---|---|
| url | string | SI | URL or bare domain to analyze (e.g. example.com) |
| mode | string | NO | single (default) or sitemap |
| bypass_cache | bool | NO | Force fresh analysis, ignoring the 60-min cache (default false) |
| webhook_url | string | NO | HTTPS URL to POST when scan completes (JSON body with scan_id, status, result) |
Response 202 Accepted
/api/v1/scans/{scan_id}
scope: read
Retrieves status and results of a scan. Poll every 2-3 seconds until status != "running".
running
Running
complete
Completed
error
Failed
stopped
Stopped
Bulk scan
/api/v1/scans/bulk
scope: scan
Starts parallel scans for multiple URLs (up to 50). Returns a batch_id to track progress.
| Field | Type | Req. | Description |
|---|---|---|---|
| urls | array | SI | Array of URLs/domains to scan (max 50) |
| mode | string | NO | single (default) |
| bypass_cache | bool | NO | Force fresh analysis for all URLs |
Response 202 Accepted
/api/v1/scans/bulk/{batch_id}
scope: read
Polls the status of a bulk batch. Returns partial results as scans complete.
Response (in progress)
History
/api/v1/history
scope: read
User scan history with pagination.
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | int | 1 | Page number |
| per_page | int | 20 | Results per page (max 50) |
Export
/api/v1/scans/{id}/export/{format}
scope: export
Exports scan results. Supported formats: json, csv, pdf.
Crawls
Start and monitor full-site crawls. Results are returned asynchronously via polling.
/api/v1/crawls
scope: scan
Starts an asynchronous site crawl. Returns immediately with a task_id to poll for results.
| Field | Type | Required | Description |
|---|---|---|---|
| domain | string | yes | Domain or full URL to crawl |
| max_pages | int | no | Max pages (capped by plan: Free=1000, Pro=10000) |
| max_depth | int | no | Max link depth (capped by plan: Free=4, Pro=8) |
Response 202
/api/v1/crawls/{task_id}
scope: read
Polls crawl status. Status can be running, complete, error, or stopped. When complete, includes job_id and report_url.
Response (complete)
/api/v1/crawls
scope: read
Lists crawl jobs for the authenticated user (max 100).
| Parameter | Type | Default | Description |
|---|---|---|---|
| limit | int | 20 | Max results (max 100) |
Scheduled Reports
Create and manage automated SEO reports sent via email on a weekly or monthly schedule.
/api/v1/scheduled-reports
scope: read
List all scheduled reports for the authenticated user.
/api/v1/scheduled-reports
scope: write
Create a new scheduled report.
| Field | Type | Required | Description |
|---|---|---|---|
| url | string | yes | URL of the page to scan |
| schedule_type | string | yes | weekly or monthly |
| day_of_week | int | if weekly | 0 (Mon) to 6 (Sun) |
| day_of_month | int | if monthly | 1 to 28 |
| label | string | no | Optional label for the report |
| notify_email | string | no | Override email (defaults to account email) |
/api/v1/scheduled-reports/{id}
scope: write
Update a scheduled report. Accepts the same fields as POST.
/api/v1/scheduled-reports/{id}/toggle
scope: write
Toggle is_active on/off for a scheduled report.
/api/v1/scheduled-reports/{id}
scope: write
Delete a scheduled report permanently.
User
/api/v1/user/profile
scope: read
Returns the authenticated user's profile.
/api/v1/user/usage
scope: read
Usage statistics: scans today, API requests, plan limits.
Error codes
| Code | HTTP | Description |
|---|---|---|
MISSING_AUTH |
401 | Authorization header missing or malformed |
INVALID_TOKEN |
401 | Token invalid, expired or revoked |
INSUFFICIENT_SCOPE |
403 | Token does not have the required scope |
INVALID_CREDENTIALS |
401 | Wrong email/password |
ACCOUNT_DISABLED |
403 | Account disabled |
RATE_LIMIT_EXCEEDED |
429 | Scan or request limit exceeded |
INVALID_REQUEST |
400 | Missing or malformed parameters |
INVALID_URL |
400 | Invalid URL |
INVALID_SCOPES |
400 | Unrecognized scopes |
NOT_FOUND |
404 | Resource not found |
FORBIDDEN |
403 | Access denied (resource belongs to another user) |
INTERNAL_ERROR |
500 | Internal server error |