API reference (v1)

SEODiff’s API is the product. The dashboard and CI integrations are clients of the API.

Authentication

Most endpoints require an API key:

Authorization: Bearer <api_key>

Base URL

All paths are under /api/v1:

https://api.seodiff.io/api/v1

You can also call the same paths on https://seodiff.io/api/v1.

Recommended first call

If you are integrating for the first time, start with POST /api/v1/validate using wait=true. It gives one response with pass/fail plus links to artifacts.

Endpoints

GET /api/v1/me

Returns account + plan info.

GET /api/v1/sites

List monitored sites.

POST /api/v1/sites

Add or update a monitored site.

{
  "base_url": "https://example.com",
  "enabled": true,
  "schedule": "nightly",
  "config": {}
}

POST /api/v1/scan

Enqueue a scan. Returns 202 Accepted with an id and a status_url.

{
  "base_url": "https://preview.example.com",
  "render_js": false,
  "lighthouse": false
}

POST /api/v1/validate

CI-friendly wrapper around scanning. When wait is true, it waits for completion and returns a pass/fail decision plus artifact links.

{
  "base_url": "https://preview.example.com",
  "preset": "fast",
  "fail_on": "fetch_errors,non200_status,schema_missing_required,placeholder_hits",
  "max_issue_rate": 10,
  "wait": true,
  "timeout_seconds": 180
}

Response (wait=true) includes:

If waiting times out, this endpoint can return 202 with a running status. In that case, keep polling using the returned status_url and fetch artifacts when complete.

GET /api/v1/scans/{id}/summary.md

Return a Markdown summary suitable for GitHub PR comments. Use the URL returned as summary_markdown_url from /validate to keep presets and thresholds consistent.

GET /api/v1/scans/{id}/findings.json

Export normalized findings as JSON for downstream tooling.

GET /api/v1/scans/{id}/findings.csv

Export normalized findings as CSV.

GET /api/v1/incidents

List recent incidents detected by monitoring.

GET /api/v1/templates?base_url=...

List template identifiers detected for a monitored site. This is useful for building links to the drift timeline (and is used by the dashboard’s template autocomplete).

{
  "templates": [
    "/product/*",
    "/collections/*"
  ]
}

Templates appear after at least one monitoring scan has run for the given base_url.

GET /api/v1/timeline?base_url=...&template=...

List drift timeline points for a given base URL and template identifier. The template value should match one of the entries returned by /api/v1/templates.

GET /api/v1/audit

List API key audit events.

GET /api/v1/project-overview?base_url=...

Dashboard aggregate endpoint for a project. Returns project summary cards, recent scans, and gsc payload for Search Console widgets.

GET /api/v1/extraction-rules?base_url=...

List custom extraction rules for a site.

POST /api/v1/extraction-rules?base_url=...

Create or update a custom extraction rule (Pro required).

{
  "field_name": "price",
  "selector_type": "css",
  "selector": ".product-price",
  "expected_type": "number",
  "required": true
}

DELETE /api/v1/extraction-rules?base_url=...&field_name=...

Delete one extraction rule by field name (Pro required).

POST /api/v1/extraction-rules/validate

Dry-run a rule against sampled pages before saving (Pro required).

{
  "base_url": "https://example.com",
  "rule": {
    "field_name": "price",
    "selector_type": "css",
    "selector": ".product-price",
    "expected_type": "number",
    "required": true
  }
}

POST /api/v1/gsc/connect

Start Google Search Console OAuth for a site (Pro + GSC integration configured). Returns an auth_url to redirect the user.

GET /api/v1/gsc/properties?base_url=...

List available/selected Search Console properties for a connected site.

POST /api/v1/gsc/property

Set the selected Search Console property for a site.

{
  "base_url": "https://example.com",
  "property": "sc-domain:example.com"
}

POST /api/v1/gsc/sync

Trigger a fresh Search Console data sync for a site.

{
  "base_url": "https://example.com"
}

POST /api/v1/deep-audit

Start a deep crawl job (Pro/Enterprise depending on crawl_scope). Returns job_id, status_url, and report links.

{
  "base_url": "https://example.com",
  "crawl_scope": "deep_audit",
  "max_pages": 500,
  "render_js": false,
  "respect_robots": true,
  "crawl_speed": "normal",
  "include_patterns": [],
  "exclude_patterns": []
}

GET /api/v1/deep-audit/

List deep-audit jobs for the authenticated account.

GET /api/v1/deep-audit/{job_id}

Get deep-audit job status, progress, and metadata.

GET /api/v1/deep-audit/{job_id}/report

Get deep-audit HTML report (job must be complete).

GET /api/v1/deep-audit/{job_id}/json

Get raw deep-audit JSON result (job must be complete).

GET /api/v1/deep-audit/{job_id}/graph

Get template internal-link graph payload used by the app graph view.

GET /api/v1/deep-audit/{job_id}/url-pagerank

Get URL-level internal PageRank rows and summary for the deep-audit job.

GET /api/v1/deep-audit/{job_id}/full-audit

Get full audit aggregate payload for enterprise-style views.

GET /api/v1/project/{job_id}/graph

Legacy alias that redirects to /api/v1/deep-audit/{job_id}/graph.

GET /api/v1/project/{job_id}/url_pagerank

Legacy alias that redirects to /api/v1/deep-audit/{job_id}/url-pagerank.

GET /api/v1/project/{job_id}/full_audit

Legacy alias that redirects to /api/v1/deep-audit/{job_id}/full-audit.

Pass/fail behavior (today)

Error model

Errors typically return JSON shaped like:

{
  "error": "..."
}

Quota and site limits may return 429. Invalid input returns 400. Plan-gated features may return 403. Missing/invalid auth returns 401.

Planned improvements (not available yet)

API-first by design

The dashboard and automation are clients of the API. This keeps behavior consistent across monitoring and CI/CD, and allows SEODiff to evolve heuristics without changing your integration surface.

Related