API · v1.0

Flatline SEO REST API

Run audits, fetch your sites, keywords, backlinks, and visibility-score history. Stripe-shape conventions, OpenAPI 3.1 spec, available on the Agency plan.

Get API access

9

Endpoints

100/min

Per-token rate limit

24h

Idempotency window

OpenAPI 3.1

Spec format

Quickstart

Generate a token at app.flatlineseo.com/client/api-keys. The plaintext is shown once. Authenticate with the standard Authorization header.

# Run an audit
curl -X POST https://app.flatlineseo.com/api/v1/audits \
  -H "Authorization: Bearer fl_live_..." \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-site.com"}'

Full machine-readable spec: /api/openapi.json. Drop it into Stoplight, Postman, or any OpenAPI generator.

Conventions

Five Stripe-style conventions you only need to learn once. They apply to every endpoint.

Authentication

Authorization: Bearer fl_live_… on every request. The plaintext is shown once at creation; only the SHA-256 hash is stored on our side.

A ?token= query-string fallback exists for clients without custom-header support — flagged in our audit log so you can detect tokens accidentally landing in URLs.

Errors

Failures return JSON in the shape:

{"error":{"code":"invalid_request",
 "message":"...",
 "type":"invalid_request_error",
 "param":"url"}}

Dispatch on code (stable, machine-readable). Don't parse message — copy may change.

Rate limits

Three windows per token: 100/min · 600/hr · 5000/day. The tightest trips first. Every response carries X-RateLimit-Limit-*, -Remaining-*, -Reset-* headers (minute / hour / day).

429 responses include Retry-After in seconds. Back off, don't hammer.

Idempotency

Required on every POST. Send Idempotency-Key: <uuid>. Replaying the same key + body within 24h returns the cached response (and an Idempotent-Replayed: true header).

Replaying with a different body returns 409 idempotency_key_mismatch.

Pagination

Cursor-based on list endpoints. Append ?starting_after=<last_id>&limit=20 (limit max 100, default 20).

Response includes has_more and next_cursor. When has_more is false, you've hit the end.

Sandbox

Tokens prefixed fl_test_ hit the same validation but run against a fixture set — no real audits, no third-party API spend. Use them in CI.

Sandbox fixtures are returned for shape-stability testing. Don't treat the data as real customer data.

Endpoints

All endpoints are rooted at https://app.flatlineseo.com/api/v1. Method + path + a working curl + response excerpt for each.

Account

GET/me

Token + plan introspection

Useful for SDK boot. Tells you the token's owner type, the plan it inherits, and the number of sites it can see.

Request

curl https://app.flatlineseo.com/api/v1/me \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "token",
  "token": { "id": "...", "prefix": "fl_live_qK4n", "mode": "live" },
  "plan": {
    "id": "agency",
    "label": "Agency",
    "limits": { "audits_per_month": null, "max_sites": 25, ... }
  },
  "sites_count": 3,
  "rate_limits": { "per_minute": 100, "per_hour": 600, "per_day": 5000 }
}

Audits

POST/audits

Run a fresh audit

Triggers PageSpeed + on-page meta scrape and returns a visibility score 0–100 plus enumerated findings. Idempotency-Key required.

Request

curl -X POST https://app.flatlineseo.com/api/v1/audits \
  -H "Authorization: Bearer fl_live_..." \
  -H "Idempotency-Key: 1234abcd-..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "scope": "country",
    "country": "GB"
  }'

Response (excerpt)

{
  "id": "01HX...",
  "object": "audit",
  "business_id": "01HX...",
  "url": "https://example.com",
  "scope": "country",
  "country": "GB",
  "visibility_score": 78,
  "pagespeed": {
    "performance": 84,
    "seo": 91,
    "accessibility": 88,
    "best_practices": 92,
    "load_time_ms": 2140
  },
  "pagespeed_status": "ok",
  "findings": [
    {
      "severity": "warning",
      "category": "performance",
      "title": "Slow page load on mobile",
      "explanation": "Mobile load time is over 3 seconds..."
    }
  ],
  "created_at": "2026-05-19T14:23:11.000Z"
}
GET/audits/{id}

Fetch one audit

Request

curl https://app.flatlineseo.com/api/v1/audits/01HX... \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "id": "01HX...",
  "object": "audit",
  "url": "https://example.com",
  "visibility_score": 78,
  "pagespeed": { ... },
  "created_at": "2026-05-19T14:23:11.000Z"
}
GET/audits?domain=&starting_after=&limit=

List audits

Cursor-paginated. Filter by domain (apex match, case-insensitive).

Request

curl "https://app.flatlineseo.com/api/v1/audits?domain=example.com&limit=20" \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "list",
  "data": [
    { "id": "01HX...", "object": "audit", ... },
    ...
  ],
  "has_more": true,
  "next_cursor": "01HX..."
}

Sites

GET/sites

List your sites

Request

curl https://app.flatlineseo.com/api/v1/sites \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "list",
  "data": [
    {
      "id": "01HX...",
      "object": "site",
      "name": "Example Co",
      "url": "https://example.com",
      "country": "United Kingdom",
      "city": "Belfast",
      "visibility_score": 78,
      "last_scored_at": "2026-05-19T14:23:11.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
GET/sites/{id}

Fetch one site

Request

curl https://app.flatlineseo.com/api/v1/sites/01HX... \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "id": "01HX...",
  "object": "site",
  "name": "Example Co",
  "url": "https://example.com",
  "visibility_score": 78,
  "pagespeed": { "performance": 84, ... },
  "google_business_profile": {
    "rating": 4.7,
    "review_count": 142
  },
  "last_scored_at": "2026-05-19T14:23:11.000Z"
}
GET/sites/{id}/keywords

Ranked keywords

Up to 100 keywords from the cached DataForSEO enrichment. Includes position, search volume, and CPC where available.

Request

curl https://app.flatlineseo.com/api/v1/sites/01HX.../keywords \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "list",
  "data": [
    {
      "object": "keyword",
      "keyword": "belfast plumber emergency",
      "position": 7,
      "search_volume": 480,
      "url": "https://example.com/emergency",
      "cpc": 1.84
    }
  ],
  "enriched_at": "2026-05-18T09:11:00.000Z"
}
GET/sites/{id}/backlinks

Backlink summary

Total backlinks, referring domains, dofollow share, top 20 anchors.

Request

curl https://app.flatlineseo.com/api/v1/sites/01HX.../backlinks \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "backlinks",
  "total_backlinks": 1247,
  "referring_domains": 89,
  "rank": 412,
  "dofollow_share": 0.78,
  "top_anchors": [
    { "anchor": "example co belfast", "count": 84, "dofollow_share": 0.91 }
  ],
  "enriched_at": "2026-05-18T09:11:00.000Z"
}
GET/sites/{id}/score-history

Visibility-score time-series

Up to 365 score points, newest first. Drives trend charts on customer dashboards.

Request

curl https://app.flatlineseo.com/api/v1/sites/01HX.../score-history \
  -H "Authorization: Bearer fl_live_..."

Response (excerpt)

{
  "object": "list",
  "data": [
    {
      "id": "01HX...",
      "object": "score_point",
      "visibility_score": 78,
      "scope": "country",
      "country": "GB",
      "scored_at": "2026-05-19T14:23:11.000Z"
    }
  ]
}

Important

Why is there no opportunity_score?

We compute two scores internally: a public-facing 0–100 visibility_score (returned everywhere) and a 0–10 opportunity_score used only by our sales team to prioritise prospect outreach. The Public API will never return the opportunity score, by design — it would leak commercial intelligence about our prospecting.

Ready to wire it up?

Generate a key from your dashboard. Plaintext shown once. Sandbox fl_test_ keys are free.

Free SEO audit in 15 seconds

Run free audit