Skip to content
Approvalens

Developers · API v1

REST API

The same data as your account page, as JSON: monitored sites with their state and outages, your reports with score and findings, and the free AI crawler check on demand.

Create a keyRequires an active monitoring subscription

Getting started

Base URL

https://approvalens.com/api/v1

Every endpoint answers with JSON and reads only the data of the account that owns the key: its monitored sites and the reports scanned or bought with its e-mail address.

  1. 1

    Sign in and subscribe to site health monitoring ($4.99 a month): the API comes with it.

  2. 2

    Open Account → API keys, create a key and copy it: it is shown once.

  3. 3

    Send it as a bearer token with each request.

Authentication

Requires an active monitoring subscription

API access comes with the site health monitoring subscription ($4.99 a month), while it is active or cancelled but not yet ended. The month of monitoring included with a full report does not include it. Without a subscription your keys are kept, but every request answers 403 subscription_required; the same keys work again once a subscription is active.

Keys look like al_live_ followed by 32 characters. Send one in the Authorization header:

Authorization: Bearer al_live_••••••••••••••••••••••••••••••••

An account can have up to 5 active keys. Revoke a key on the account page and it stops working at once. We store only a SHA-256 fingerprint of each key, so a lost key cannot be shown again: make a new one.

The API is for servers and scripts. It sends no CORS headers, so a web page on another site cannot call it from a visitor's browser. Never put a key in front-end code.

Rate limits

60 requests a minute per key, counted over a sliding minute. Every answer carries:

  • X-RateLimit-Limit the limit (60)
  • X-RateLimit-Remaining requests left in the current minute
  • X-RateLimit-Reset when the oldest request leaves the window (Unix seconds)

Over the limit you get 429 with a Retry-After header in seconds. POST /api/v1/ai-checks also has the free tool's own limit: 6 checks a minute per key, and a site checked in the last 10 minutes gets that result back (cached: true). Requests with a wrong key are limited to 20 a minute per IP address.

429
{
  "error": "rate_limited",
  "message": "Rate limit of 60 requests per minute per key reached. Retry in 12 s."
}

Conventions

  • Times are ISO-8601 in UTC, without fractions: 2026-10-06T09:14:03Z. A missing time is null.
  • Add ?lang=tr to get human-readable text (incident descriptions, alert lines, finding titles) in Turkish; the default is English.
  • Hosts are matched with and without www.
  • Fields may be added to v1 answers; existing fields keep their name and meaning. Breaking changes get a new version in the path.

Errors

Errors use the HTTP status and a JSON body with a machine-readable code and a sentence for people:

CodeStatusMeaning
missing_key401No Authorization: Bearer header.
invalid_key401The key is malformed, unknown or revoked.
subscription_required403The account has no active monitoring subscription. The same keys work again once it has one.
rate_limited429Too many requests: wait Retry-After seconds.
bad_request400A parameter or the JSON body is not valid.
not_found404No such endpoint, or nothing with that id or host on your account.
unreachable422AI check only: the site did not answer.
unavailable503Our side failed. Try again shortly.

Endpoints

Shapes are exact; the values are an example.

GET/api/v1/sites

List monitored sites

Every site monitored for your account, with its state now: up or down, 30-day uptime, TLS days left, ads.txt, how many AI crawlers can read the homepage, the last and next daily check, and the outage going on, if any. monitoring is false once the subscription or the month included with a report has ended.

Example request
curl https://approvalens.com/api/v1/sites \
  -H "Authorization: Bearer $APPROVALENS_KEY"
Example response
{
  "sites": [
    {
      "host": "example.com",
      "url": "https://example.com/",
      "status": "up",
      "monitoring": true,
      "plan": {
        "status": "active",
        "source": "subscription",
        "renews_at": "2026-10-25T10:00:00Z",
        "ends_at": null,
        "included_until": null,
        "test": false
      },
      "uptime_30d": 99.93,
      "tls_valid": true,
      "tls_days_left": 41,
      "tls_expires_at": "2026-11-16T12:00:00Z",
      "ads_txt": "found",
      "ai_allowed": 11,
      "ai_total": 14,
      "last_check": "2026-10-06T05:00:00Z",
      "next_check": "2026-10-07T05:00:00Z",
      "last_uptime_probe": "2026-10-06T09:58:00Z",
      "open_incident": null,
      "alerts_enabled": true
    }
  ]
}

GET/api/v1/sites/{host}

One monitored site

Everything in the list, plus the AI crawler breakdown, the 5 most recent outages and the 10 most recent alerts (with the lines the e-mail said and whether it was sent).

Parameters

host
the site, with or without www
Example request
curl https://approvalens.com/api/v1/sites/example.com \
  -H "Authorization: Bearer $APPROVALENS_KEY"
Example response
{
  "site": {
    "host": "example.com",
    "url": "https://example.com/",
    "status": "up",
    "monitoring": true,
    "plan": {
      "status": "active",
      "source": "subscription",
      "renews_at": "2026-10-25T10:00:00Z",
      "ends_at": null,
      "included_until": null,
      "test": false
    },
    "uptime_30d": 99.93,
    "tls_valid": true,
    "tls_days_left": 41,
    "tls_expires_at": "2026-11-16T12:00:00Z",
    "ads_txt": "found",
    "ai_allowed": 11,
    "ai_total": 14,
    "last_check": "2026-10-06T05:00:00Z",
    "next_check": "2026-10-07T05:00:00Z",
    "last_uptime_probe": "2026-10-06T09:58:00Z",
    "open_incident": null,
    "alerts_enabled": true,
    "ai_crawlers": {
      "allowed": 11,
      "blocked_by_robots": 2,
      "blocked_by_server": 1,
      "unknown": 0,
      "total": 14
    },
    "pending_confirmation": [],
    "latest_check_url": "https://approvalens.com/ai/Xk2v9QmL0pRa",
    "incidents": [
      {
        "id": 12,
        "started_at": "2026-10-03T10:00:00Z",
        "ended_at": "2026-10-03T10:25:00Z",
        "ongoing": false,
        "duration_seconds": 1500,
        "reason": "http_502",
        "http_status": 502,
        "description": "HTTP 502"
      }
    ],
    "alerts": [
      {
        "id": 87,
        "at": "2026-10-03T10:25:00Z",
        "kind": "up",
        "emailed": true,
        "lines": [
          "Your homepage answers again. It was down for 25 minutes (Oct 3, 2026 08:00 UTC – Oct 3, 2026 08:25 UTC). Reason seen: HTTP 502."
        ],
        "check_id": null
      },
      {
        "id": 86,
        "at": "2026-10-03T10:10:00Z",
        "kind": "down",
        "emailed": true,
        "lines": [
          "example.com is down · HTTP 502"
        ],
        "check_id": null
      }
    ]
  }
}

GET/api/v1/sites/{host}/incidents

Outages of a site

Outages found by the 5-minute uptime check that ended after since or are still going on, newest first. An outage opens after two failed checks in a row.

Parameters

host
the site, with or without www
since
ISO-8601 date or time; default 30 days ago
limit
1–500, default 100
Example request
curl "https://approvalens.com/api/v1/sites/example.com/incidents?since=2026-09-06" \
  -H "Authorization: Bearer $APPROVALENS_KEY"
Example response
{
  "host": "example.com",
  "since": "2026-09-06T08:00:00Z",
  "incidents": [
    {
      "id": 12,
      "started_at": "2026-10-03T10:00:00Z",
      "ended_at": "2026-10-03T10:25:00Z",
      "ongoing": false,
      "duration_seconds": 1500,
      "reason": "http_502",
      "http_status": 502,
      "description": "HTTP 502"
    }
  ]
}

GET/api/v1/reports

List your reports

Scans you ran while signed in and reports bought with your e-mail address, newest first: score and verdict (null until a scan is done, or when the site blocked us), when the report is unlocked until, and the deep scan an unlock started.

Example request
curl https://approvalens.com/api/v1/reports \
  -H "Authorization: Bearer $APPROVALENS_KEY"
Example response
{
  "reports": [
    {
      "id": "q7RkT2mYw9Lb3xNc",
      "host": "example.com",
      "url": "https://example.com/",
      "status": "done",
      "score": 78,
      "verdict": "almost",
      "created_at": "2026-10-04T10:00:00Z",
      "finished_at": "2026-10-04T10:06:50Z",
      "unlocked": true,
      "unlocked_until": "2026-11-03T10:00:00Z",
      "ai_unlocked_until": null,
      "deep_scan": {
        "id": "Hn4sP0dVe8KqZ1aY",
        "status": "done",
        "progress": 100
      },
      "report_url": "https://approvalens.com/scan/q7RkT2mYw9Lb3xNc"
    }
  ]
}

GET/api/v1/reports/{id}

One report

Score, verdict, issue counts by severity, category scores and every failing finding with its title and severity. The pages and parameters behind a finding (evidence) are included only when your account has the site unlocked: everything for a full report, the AI findings for an AI visibility report.

Parameters

id
the report id from the list
Example request
curl https://approvalens.com/api/v1/reports/q7RkT2mYw9Lb3xNc \
  -H "Authorization: Bearer $APPROVALENS_KEY"
Example response
{
  "report": {
    "id": "q7RkT2mYw9Lb3xNc",
    "host": "example.com",
    "url": "https://example.com/",
    "status": "done",
    "score": 78,
    "verdict": "almost",
    "created_at": "2026-10-04T10:00:00Z",
    "finished_at": "2026-10-04T10:06:50Z",
    "unlocked": true,
    "unlocked_until": "2026-11-03T10:00:00Z",
    "ai_unlocked": true,
    "ai_unlocked_until": null,
    "report_url": "https://approvalens.com/scan/q7RkT2mYw9Lb3xNc",
    "counts": {
      "blocker": 0,
      "critical": 1,
      "warning": 3,
      "notice": 2,
      "pass": 74
    },
    "categories": [
      {
        "id": "content",
        "score": 71
      },
      {
        "id": "trust",
        "score": 90
      }
    ],
    "pages_scanned": 50,
    "findings": [
      {
        "id": "content.thin_pages",
        "title": "Thin articles",
        "category": "content",
        "severity": "critical",
        "level": "official",
        "evidence_total": 26,
        "unlocked": true,
        "params": {
          "thin": 26,
          "very_thin": 9,
          "of": 42,
          "pct": 62,
          "median": 131,
          "tools": 0
        },
        "evidence": [
          {
            "url": "https://example.com/recipes/quick-salsa/",
            "detail": "96 words"
          },
          {
            "url": "https://example.com/recipes/lemonade/",
            "detail": "118 words (+240 words of menus/footer)"
          }
        ]
      },
      {
        "id": "trust.contact_missing",
        "title": "Contact information",
        "category": "trust",
        "severity": "warning",
        "level": "official",
        "evidence_total": 0,
        "unlocked": true,
        "params": {},
        "evidence": []
      }
    ]
  }
}

POST/api/v1/ai-checks

Run an AI crawler check

Runs the free “Can AI see your site?” check of one homepage (about 20 seconds) and returns the full result: each AI crawler's robots.txt rule and simulated request, meta directives, llms.txt and the sitemap. 201 for a new check, 200 for a cached one.

Parameters

url
JSON body: the site's address
Example request
curl -X POST https://approvalens.com/api/v1/ai-checks \
  -H "Authorization: Bearer $APPROVALENS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
Example response
{
  "check": {
    "id": "aic_7Qm2xK9pLs",
    "url": "greenleaf-journal.example",
    "final_url": "https://www.greenleaf-journal.example/",
    "host": "www.greenleaf-journal.example",
    "checked_at": "2026-10-06T12:45:00Z",
    "duration_ms": 17420,
    "cached": false,
    "headline": {
      "key": "blocked_server",
      "bot": "ChatGPT-User",
      "product": "ChatGPT"
    },
    "summary": {
      "allowed": 6,
      "blocked_robots": 4,
      "blocked_server": 3,
      "unknown": 1,
      "total": 14
    },
    "bots": [
      {
        "id": "oai-searchbot",
        "token": "OAI-SearchBot",
        "name": "OAI-SearchBot",
        "vendor": "OpenAI",
        "product": "ChatGPT",
        "purpose": "search",
        "kind": "fetcher",
        "doc_url": "https://developers.openai.com/api/docs/bots",
        "robots_respected": true,
        "robots": {
          "allowed": true,
          "group": "*",
          "rule": null
        },
        "http": {
          "simulated": true,
          "status": 200,
          "verdict": "ok",
          "reason": "200 OK, same page as a browser",
          "similarity": 0.98,
          "headers": {
            "content-type": "text/html; charset=utf-8"
          }
        },
        "verdict": "allowed"
      }
    ],
    "robots": {
      "url": "https://www.greenleaf-journal.example/robots.txt",
      "status": 200,
      "found": true,
      "unavailable": false,
      "excerpt": "User-agent: *\nDisallow: /wp-admin/\nAllow: /wp-admin/admin-ajax.php\n\nUser-agent: GPTBot\nDisallow: /\n\nUser-agent: CCBot\nDisallow: /\n\nUser-agent: Bytespider\nDisallow: /\n\nUser-agent: Google-Extended\nDisallow: /\n\nSitemap: https://www.greenleaf-journal.example/sitemap_index.xml"
    },
    "directives": {
      "meta": [
        {
          "name": "robots",
          "content": "index, follow, noai, noimageai"
        }
      ],
      "x_robots_tag": [],
      "flags": {
        "noai": true,
        "noimageai": true,
        "noindex": false,
        "nosnippet": false
      }
    },
    "js": {
      "raw_words": 412,
      "rendered_words": 1860,
      "ratio": 0.22,
      "verdict": "js_dependent",
      "reason": ""
    },
    "llms": {
      "url": "https://www.greenleaf-journal.example/llms.txt",
      "status": 200,
      "found": true,
      "content_type": "text/html; charset=utf-8",
      "h1": "Greenleaf Journal",
      "summary": null,
      "sections": 3,
      "links": 18,
      "problems": [
        {
          "code": "no_summary",
          "detail": "No blockquote summary after the H1",
          "line": 2
        },
        {
          "code": "content_type",
          "detail": "Served as text/html; expected text/plain or text/markdown",
          "line": null
        },
        {
          "code": "bad_list_item",
          "detail": "Several links on one list line",
          "line": 14
        }
      ]
    },
    "sitemap": {
      "sitemaps": [
        {
          "url": "https://www.greenleaf-journal.example/sitemap_index.xml",
          "status": 200,
          "valid": true,
          "blocked_for": [
            "gptbot",
            "ccbot",
            "bytespider",
            "google-extended"
          ]
        },
        {
          "url": "https://www.greenleaf-journal.example/post-sitemap.xml",
          "status": 200,
          "valid": true,
          "blocked_for": [
            "gptbot",
            "ccbot",
            "bytespider",
            "google-extended"
          ]
        }
      ],
      "sampled": 20,
      "resolved": 19,
      "problems": [
        {
          "code": "blocked_for_ai",
          "detail": "robots.txt blocks 4 AI crawlers from the URLs this sitemap lists"
        }
      ]
    },
    "result_url": "https://approvalens.com/ai/aic_7Qm2xK9pLs"
  }
}

Changelog

  1. v1 · 2026-10-06First version: sites, incidents, reports, report summary, AI checks.
  2. —Server monitoring endpoints will be added here when that feature launches.