Domain vetting
Check a domain before you buy it, and get told when a new aged domain matches a search you saved.
Domain vetting: credits and usage
GET/api/v1/domain-vettingScope vetting:read
How many report credits this account holds, how many reports it has run, and the prices.
Example
curl -s "https://app.pbn.ltd/api/v1/domain-vetting" \
-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/domain-vetting", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-vetting", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"credits": 7,
"unlimited": false,
"reports": 12,
"price_per_report_from": "1.38",
"free_with_every_aged_domain": 1
}
}
Errors: rate_limited, scope_missing, unauthorized
List your vetting reports
GET/api/v1/domain-vetting/reportsScope vetting:read
Every vetting report this account has run, newest first, with its verdict and score.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
verdict | query | string (one of: clean, care, risk) | no | Only reports with this verdict. |
search | query | string | no | Part of the domain name. |
limit | query | integer | no | Items per page. Default: 50. |
cursor | query | string | no | next_cursor of the previous page. |
Example
curl -s "https://app.pbn.ltd/api/v1/domain-vetting/reports" \
-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/domain-vetting/reports", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-vetting/reports", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": [
{
"id": 51,
"domain": "example.com",
"state": "ready",
"score": 68,
"verdict": "care",
"created_at": "2026-09-22T10:00:00Z"
}
],
"next_cursor": null,
"has_more": false
}
Errors: rate_limited, scope_missing, unauthorized
One vetting report
GET/api/v1/domain-vetting/reports/{report_id}Scope vetting:read
The whole report: the verdict, every reason, the key numbers, the anchor texts, the link and traffic history and what the site was in the web archive.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
report_id | path | integer | yes | The report id. |
Example
curl -s "https://app.pbn.ltd/api/v1/domain-vetting/reports/report_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/domain-vetting/reports/report_id", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-vetting/reports/report_id", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"id": 51,
"domain": "example.com",
"state": "ready",
"score": 68,
"verdict": "care",
"created_at": "2026-09-22T10:00:00Z",
"credits_used": 1,
"summary": "Proceed with care (68/100). Read the reasons below before you buy.",
"reasons": [
{
"weight": -12,
"text": "Raised spam score (41/100): ...",
"area": "links"
}
],
"facts": {
"referring_domains": 177,
"backlinks": 23794,
"spam_score": 40,
"keywords": 0,
"traffic": 0,
"indexed": false,
"archived_from": "2019-01",
"registered": "2018-11-02",
"expires": "2026-11-02"
}
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized
Vet a domain
POST/api/v1/domain-vetting/reportsScope vetting:write
Runs a full report and returns it. Spends one report credit, unless you already vetted this domain recently - then the report you already have comes back and nothing is charged.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
domain | body | string | yes | The domain to vet, e.g. example.com. |
location_code | body | integer | no | The market its search data is read for (2840 = United States). Default: 2840. |
Example
curl -s -X POST "https://app.pbn.ltd/api/v1/domain-vetting/reports" \
-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/domain-vetting/reports", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-vetting/reports", {
method: "POST",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
201
{
"data": {
"id": 51,
"domain": "example.com",
"state": "ready",
"score": 68,
"verdict": "care",
"created_at": "2026-09-22T10:00:00Z",
"credits_used": 1,
"summary": "Proceed with care (68/100). Read the reasons below before you buy.",
"reasons": [
{
"weight": -12,
"text": "Raised spam score (41/100): ...",
"area": "links"
}
],
"facts": {
"referring_domains": 177,
"backlinks": 23794,
"spam_score": 40,
"keywords": 0,
"traffic": 0,
"indexed": false,
"archived_from": "2019-01",
"registered": "2018-11-02",
"expires": "2026-11-02"
}
}
}
Errors: payment_required, rate_limited, scope_missing, unauthorized, validation_failed
List your saved domain searches
GET/api/v1/domain-alertsScope vetting:read
Every aged-domain search you saved, what it looks for and how many domains match it now.
Example
curl -s "https://app.pbn.ltd/api/v1/domain-alerts" \
-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/domain-alerts", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-alerts", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": [
{
"id": 9,
"name": "DR 30+ finance .com",
"filters": "TLD .com, Ahrefs DR at least 30",
"active": true,
"matching_now": 14,
"last_email": "2026-09-21T06:15:00Z"
}
]
}
Errors: rate_limited, scope_missing, unauthorized
Save a domain search
POST/api/v1/domain-alertsScope vetting:write
Domains matching it today are the starting point, not news: from now on you get an e-mail when a NEW one matches.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
name | body | string | no | What to call it (we name it after the filters if empty). |
filters | body | string | no | The aged-domain list's own filter, as a query string, e.g. "tld=.com&dr_min=30&price_max=300". |
Example
curl -s -X POST "https://app.pbn.ltd/api/v1/domain-alerts" \
-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/domain-alerts", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-alerts", {
method: "POST",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
201
{
"data": {
"id": 9,
"name": "DR 30+ .com",
"filters": "TLD .com, Ahrefs DR at least 30",
"matching_now": 14
}
}
Errors: payment_required, rate_limited, scope_missing, unauthorized, validation_failed
The domains a saved search matches now
GET/api/v1/domain-alerts/{alert_id}/matchesScope vetting:read
The aged domains this saved search matches at this moment, with the price you would pay and a link to each listing.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
alert_id | path | integer | yes | The saved search id. |
limit | query | integer | no | How many to return. Default: 50. |
Example
curl -s "https://app.pbn.ltd/api/v1/domain-alerts/alert_id/matches" \
-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/domain-alerts/alert_id/matches", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-alerts/alert_id/matches", {
method: "GET",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": [
{
"domain": "example.com",
"price_usd": "129.00",
"dr": 34,
"referring_domains": 212,
"monthly_traffic": 900,
"listing_url": "https://app.pbn.ltd/domains/domain/1234"
}
]
}
Errors: not_found, rate_limited, scope_missing, unauthorized
Delete a saved search
DELETE/api/v1/domain-alerts/{alert_id}Scope vetting:write · destructive
Deletes the saved search and stops its e-mails. What it already told you about is forgotten with it.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
alert_id | path | integer | yes | The saved search id. |
Example
curl -s -X DELETE "https://app.pbn.ltd/api/v1/domain-alerts/alert_id" \
-H "Authorization: Bearer $PBN_API_KEY"
import os
import requests
headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.delete("https://app.pbn.ltd/api/v1/domain-alerts/alert_id", headers=headers, timeout=120)
print(r.status_code, r.json())
const res = await fetch("https://app.pbn.ltd/api/v1/domain-alerts/alert_id", {
method: "DELETE",
headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
Response
200
{
"data": {
"deleted": true,
"id": 9
}
}
Errors: not_found, rate_limited, scope_missing, unauthorized