PBN.LTD API docs
View as Markdown

Site audit

Crawl a site you own and find what is holding it back, with a fix for each finding. Richer for sites hosted with us.

Site audit: plan and usage

GET/api/v1/site-audit

Scope audit:read

Your plan, audits a month included and used, the page cap per audit, and your most recent audit.

Example

curl -s "https://app.pbn.ltd/api/v1/site-audit" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/site-audit", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "active": true,
    "plan": "Growth",
    "paid_until": "2026-10-31",
    "audits_this_month": {
      "used": 3,
      "limit": 25
    },
    "pages_per_audit": 300,
    "scheduled_reaudits": true,
    "latest": {
      "id": 88,
      "host": "example.com",
      "state": "done",
      "score": 74,
      "grade": "C",
      "pages_crawled": 100,
      "issues": 12,
      "critical": 1,
      "warnings": 6,
      "notices": 5,
      "hosted": true,
      "verified": true,
      "finished_at": "2026-09-22T09:00:00Z"
    }
  }
}

Errors: rate_limited, scope_missing, unauthorized

List audits

GET/api/v1/site-audit/audits

Scope audit:read

Your finished audits, newest first.

Parameters

NameInTypeRequiredDescription
hostquerystringnoOnly audits of this site.
limitqueryintegernoDefault: 25.
cursorquerystringnonext_cursor of the previous page.

Example

curl -s "https://app.pbn.ltd/api/v1/site-audit/audits" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/site-audit/audits", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/audits", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": [
    {
      "id": 88,
      "host": "example.com",
      "state": "done",
      "score": 74,
      "grade": "C",
      "pages_crawled": 100,
      "issues": 12,
      "critical": 1,
      "warnings": 6,
      "notices": 5,
      "hosted": true,
      "verified": true,
      "finished_at": "2026-09-22T09:00:00Z"
    }
  ],
  "next_cursor": null,
  "has_more": false
}

Errors: rate_limited, scope_missing, unauthorized

One audit and its findings

GET/api/v1/site-audit/audits/{audit_id}

Scope audit:read

The audit with every finding: what it is, what it means, which pages it affects and how to fix it. A finding with source: server comes from your hosting with us rather than from the crawl.

Parameters

NameInTypeRequiredDescription
audit_idpathintegeryesThe audit id.

Example

curl -s "https://app.pbn.ltd/api/v1/site-audit/audits/audit_id" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/site-audit/audits/audit_id", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/audits/audit_id", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "id": 88,
    "host": "example.com",
    "state": "done",
    "score": 74,
    "grade": "C",
    "pages_crawled": 100,
    "issues": [
      {
        "code": "title_duplicate",
        "severity": "warning",
        "source": "crawl",
        "title": "8 pages share a title with another page",
        "what_it_means": "When several pages carry the same title ...",
        "how_to_fix": "Give every page a title that describes that page ...",
        "pages": [
          "https://example.com/a",
          "https://example.com/b"
        ],
        "count": 8
      }
    ],
    "critical": 1,
    "warnings": 6,
    "notices": 5,
    "hosted": true,
    "verified": true,
    "finished_at": "2026-09-22T09:00:00Z"
  }
}

Errors: not_found, rate_limited, scope_missing, unauthorized

The pages an audit fetched

GET/api/v1/site-audit/audits/{audit_id}/pages

Scope audit:read

Every page the crawl fetched, with what was measured on it.

Parameters

NameInTypeRequiredDescription
audit_idpathintegeryesThe audit id.

Example

curl -s "https://app.pbn.ltd/api/v1/site-audit/audits/audit_id/pages" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/site-audit/audits/audit_id/pages", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/audits/audit_id/pages", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "items": [
      {
        "url": "https://example.com/",
        "status": 200,
        "title": "Home",
        "words": 820,
        "load_ms": 410,
        "noindex": false
      }
    ],
    "total": 100
  },
  "next_cursor": null,
  "has_more": false
}

Errors: not_found, rate_limited, scope_missing, unauthorized

Audit a site

POST/api/v1/site-audit/audits

Scope audit:write

Queues an audit; results are usually ready within a few minutes - poll /site-audit/audits/{id}. A site whose ownership you have not proved is crawled shallowly (see pages in the response); verify it to unlock a full crawl.

Parameters

NameInTypeRequiredDescription
urlbodystringyesThe site to audit, e.g. https://example.com/

Example

curl -s -X POST "https://app.pbn.ltd/api/v1/site-audit/audits" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/site-audit/audits", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/audits", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

202

{
  "data": {
    "queued": true,
    "audit_id": 89,
    "pages": 300,
    "verified": true
  }
}

Errors: payment_required, rate_limited, scope_missing, unauthorized, validation_failed

How to prove a site is yours

GET/api/v1/site-audit/verification

Scope audit:read

The three ways to prove a site is yours. Any one of them is enough, and a site hosted with us needs none.

Parameters

NameInTypeRequiredDescription
hostquerystringyese.g. example.com

Example

curl -s "https://app.pbn.ltd/api/v1/site-audit/verification" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/site-audit/verification", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/verification", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "host": "example.com",
    "verified": false,
    "method": null,
    "dns": {
      "name": "_pbn-site-audit.example.com",
      "type": "TXT",
      "value": "pbn-site-audit=..."
    },
    "meta": "<meta name=\"pbn-site-audit\" content=\"pbn-site-audit=...\">",
    "file": {
      "path": "/.well-known/pbn-site-audit.txt",
      "contents": "pbn-site-audit=..."
    }
  }
}

Errors: rate_limited, scope_missing, unauthorized

Check the proof now

POST/api/v1/site-audit/verification

Scope audit:write

Looks for the DNS record, the meta tag and the file, in that order.

Parameters

NameInTypeRequiredDescription
hostbodystringyese.g. example.com

Example

curl -s -X POST "https://app.pbn.ltd/api/v1/site-audit/verification" \
  -H "Authorization: Bearer $PBN_API_KEY"
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.post("https://app.pbn.ltd/api/v1/site-audit/verification", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/site-audit/verification", {
  method: "POST",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());

Response

200

{
  "data": {
    "verified": true,
    "method": "dns",
    "message": "Verified. Full audits are unlocked for this site."
  }
}

Errors: rate_limited, scope_missing, unauthorized, validation_failed