Guide
Queued actions
Checks and crawls can take from seconds to minutes, so the API queues them instead of making you wait on an open connection. You start the action, get a job back straight away, and poll the job until it finishes.
How it works
- Call an action, such as check DNS. It answers
202 Acceptedwith ajobIdand astatusUrl. - Call GET /jobs/{jobId} every few seconds until
statusisdoneorfailed. - Read the outcome from the job’s
result, or fetch fresh data, such as the health summary.
Jobs are kept for 24 hours. Statuses go queued → running → done or failed.
Prefer not to poll? Use webhooks to hear about downtime and findings as they happen.
1. Start an action
curl -X POST 'https://trackerv2.marketingplanet.global/api/v1/projects/6650a4c2e1b3d5f7a9c1e301/checks/dns' \
-H 'Authorization: Bearer tk_live_YOUR_KEY'
const response = await fetch('https://trackerv2.marketingplanet.global/api/v1/projects/6650a4c2e1b3d5f7a9c1e301/checks/dns', {
method: 'POST',
headers: {
Authorization: 'Bearer tk_live_YOUR_KEY',
},
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
console.log(result.data);
import requests
response = requests.post(
"https://trackerv2.marketingplanet.global/api/v1/projects/6650a4c2e1b3d5f7a9c1e301/checks/dns",
headers={"Authorization": "Bearer tk_live_YOUR_KEY"},
)
result = response.json()
if not response.ok:
raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
print(result["data"])
{
"data": {
"jobId": "6654e8a6c5f7b9d1e3a5c701",
"kind": "dns-check",
"status": "queued",
"deduplicated": false,
"statusUrl": "/api/v1/jobs/6654e8a6c5f7b9d1e3a5c701"
}
}
2. Poll the job
curl 'https://trackerv2.marketingplanet.global/api/v1/jobs/6654e8a6c5f7b9d1e3a5c701' \
-H 'Authorization: Bearer tk_live_YOUR_KEY'
const response = await fetch('https://trackerv2.marketingplanet.global/api/v1/jobs/6654e8a6c5f7b9d1e3a5c701', {
headers: {
Authorization: 'Bearer tk_live_YOUR_KEY',
},
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
console.log(result.data);
import requests
response = requests.get(
"https://trackerv2.marketingplanet.global/api/v1/jobs/6654e8a6c5f7b9d1e3a5c701",
headers={"Authorization": "Bearer tk_live_YOUR_KEY"},
)
result = response.json()
if not response.ok:
raise RuntimeError(f"{result['error']['code']}: {result['error']['message']}")
print(result["data"])
{
"data": {
"id": "6654e8a6c5f7b9d1e3a5c701",
"kind": "dns-check",
"projectId": "6650a4c2e1b3d5f7a9c1e301",
"pageId": null,
"status": "done",
"result": {
"status": "ok",
"monitors": 4,
"changed": 0
},
"errorClass": null,
"errorMessage": null,
"createdAt": "2026-10-06T09:30:00.000Z",
"startedAt": "2026-10-06T09:30:01.000Z",
"finishedAt": "2026-10-06T09:30:03.000Z"
}
}
A complete example
Start a DNS check and wait for the result, polling every 2 seconds for up to 2 minutes:
const API = 'https://trackerv2.marketingplanet.global/api/v1';
const headers = { Authorization: `Bearer ${process.env.TRACKER_API_KEY}` };
async function runAndWait(projectId) {
const start = await fetch(`${API}/projects/${projectId}/checks/dns`, {
method: 'POST',
headers,
});
const { data: queued } = await start.json();
for (let attempt = 0; attempt < 60; attempt++) {
await new Promise((r) => setTimeout(r, 2000)); // every 2 seconds
const res = await fetch(`${API}/jobs/${queued.jobId}`, { headers });
const { data: job } = await res.json();
if (job.status === 'done') return job.result;
if (job.status === 'failed') throw new Error(job.errorMessage);
}
throw new Error('Job did not finish in 2 minutes');
}
import os
import time
import requests
API = "https://trackerv2.marketingplanet.global/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['TRACKER_API_KEY']}"}
def run_and_wait(project_id):
queued = requests.post(f"{API}/projects/{project_id}/checks/dns", headers=HEADERS).json()["data"]
for _ in range(60):
time.sleep(2) # every 2 seconds
job = requests.get(f"{API}/jobs/{queued['jobId']}", headers=HEADERS).json()["data"]
if job["status"] == "done":
return job["result"]
if job["status"] == "failed":
raise RuntimeError(job["errorMessage"])
raise TimeoutError("Job did not finish in 2 minutes")
Safe retries
If the same action is already queued or running for that project (or page), the API returns that job with "deduplicated": true instead of starting another. So retrying after a timeout never piles up duplicate work, and checks started from the dashboard count too.
The uptime probe is the exception: it runs immediately and returns the result, counts against the project owner’s monthly check budget, and is limited to one per project every 30 seconds.
Queued actions
-
POST
Run a full project check
/api/v1/projects/{id}/checks/full -
POST
Check DNS
/api/v1/projects/{id}/checks/dns -
POST
Check the sitemap
/api/v1/projects/{id}/checks/sitemap -
POST
Check robots.txt
/api/v1/projects/{id}/checks/robots -
POST
Check llms.txt
/api/v1/projects/{id}/checks/llm -
POST
Check the UDP port
/api/v1/projects/{id}/checks/udp -
POST
Check domain expiry
/api/v1/projects/{id}/checks/domain-expiry -
POST
Recheck broken URLs
/api/v1/projects/{id}/checks/broken-urls -
POST
Run PageSpeed
/api/v1/projects/{id}/checks/pagespeed -
POST
Crawl a page
/api/v1/projects/{id}/pages/{pageId}/crawl