API

List your sites, start a crawl and read its affiliate link rows over REST. Create a key on the API keys page, where it is shown once. Every response is JSON except the CSV export.

Plan and authentication

API access is included with the Business plan at $29 a month, which carries 50,000 API calls a month. A plan without API access, including the Pro plan a trial grants, answers 403 with this sentence:

API access is included with the Business plan ($29/mo). Your plan does not include it, and the trial grants Pro, which does not include it either.

Send the key on every request in the x-api-key header. An Authorization: Bearer header is read too:

curl https://affiliatelinkchecker.com/api/v1/sites \
  -H "x-api-key: sk_your_key"

A missing, unknown or revoked key is 401. A key belongs to one account, and every request is answered for that account only: a crawl id that belongs to somebody else answers exactly like one that does not exist.

Rate limit and metering

Endpoints

All requests go to https://affiliatelinkchecker.com.

GET /api/v1/sites

The account's sites, sorted by host, with the id a crawl is started on.

curl https://affiliatelinkchecker.com/api/v1/sites \
  -H "x-api-key: sk_your_key"
{
  "sites": [
    {
      "id": "clz7x2m4p0001abcd1234efgh",
      "host": "https://example.com",
      "verified": true,
      "verifiedAt": "2026-10-04T09:12:44.000Z",
      "createdAt": "2026-10-03T16:40:02.000Z"
    }
  ]
}

host is the origin, with no trailing slash. verified is true once control of the host has been proved, which is required before that site can be crawled. verifiedAt is null until then.

POST /api/v1/sites/{id}/crawls

Start one crawl of one site. The answer is 202 with the crawl id, which is what the three routes below take.

curl -X POST https://affiliatelinkchecker.com/api/v1/sites/clz7x2m4p0001abcd1234efgh/crawls \
  -H "x-api-key: sk_your_key" \
  -H "x-request-id: 2026-10-11-homepage"
{
  "crawlId": "clz9h8m4c0002ijkl5678mnop",
  "status": "PENDING",
  "maxPages": 20000
}

status is PENDING at this point. maxPages is the page cap this crawl was created with. A site that is not verified is 409, a crawl already running on that site is 409, a full plan is 402, a spent monthly crawl allowance is 429, and a queue that refused the job is 503. Nothing is created and nothing is charged before one of those refusals.

GET /api/v1/crawls/{id}

One crawl: its status, its progress counters and its times. Poll this after starting a crawl.

curl https://affiliatelinkchecker.com/api/v1/crawls/clz9h8m4c0002ijkl5678mnop \
  -H "x-api-key: sk_your_key"
{
  "id": "clz9h8m4c0002ijkl5678mnop",
  "status": "COMPLETED",
  "maxPages": 20000,
  "pagesCrawled": 128,
  "pagesFailed": 3,
  "pauseCount": 1,
  "resumeAt": null,
  "stopReason": null,
  "startedAt": "2026-10-11T09:30:02.000Z",
  "finishedAt": "2026-10-11T09:36:51.000Z",
  "createdAt": "2026-10-11T09:30:01.000Z",
  "siteId": "clz7x2m4p0001abcd1234efgh",
  "site": { "host": "https://example.com" },
  "sitemapUrlCount": 131
}

status is one of PENDING, RUNNING, PAUSED, ANALYZING, COMPLETED, FAILED or CANCELED. pagesCrawled and pagesFailed are the counts so far, and sitemapUrlCount is how many URLs the sitemap listed. pauseCount counts the pauses, and resumeAt carries the time a paused crawl resumes. stopReason explains a crawl that failed. The three times are null until they happen. A crawl id that is not yours is 404.

GET /api/v1/crawls/{id}/links?issue=<kind>

One crawl's affiliate link rows: the page each link was found on, the link, its network, its tag, the issues found and where it resolves.

curl "https://affiliatelinkchecker.com/api/v1/crawls/clz9h8m4c0002ijkl5678mnop/links?issue=missing%20tag" \
  -H "x-api-key: sk_your_key"
{
  "crawlId": "clz9h8m4c0002ijkl5678mnop",
  "total": 1,
  "links": [
    {
      "page": "https://example.com/kitchen/best-kettles",
      "link": "https://www.amazon.co.uk/dp/B000000000?tag=example-21",
      "network": "amazon",
      "tag": "example-21",
      "issues": ["missing rel=sponsored or nofollow"],
      "outcome": "ok"
    }
  ]
}

page is the URL the link was found on, link is the href, and network is the network id: amazon, shareasale, cj, impact, awin, rakuten or generic. tag is the affiliate id read from the link, or null when the link carries none. issues is an array of issue strings, empty when the link is fine. outcome is ok, not found (404), gone (410), redirect loop, too many redirects, timeout, blocked by the network or blocked: private address. Only rows that have been resolved are returned.

issue matches one exact issue string: missing tag, not your tag (the id found), short link, check after redirect, missing rel=sponsored or nofollow, or marketplace co.uk differs from your default com with the two marketplaces of that link. Leave it out for every row. total is the number of rows in this answer. A crawl id that is not yours is 404.

GET /api/v1/crawls/{id}/export/links

The links.csv file of a crawl, built by the same code the dashboard export button uses, so the file and the page cannot disagree. The response is an attachment named links.csv with a text/csv content type.

curl https://affiliatelinkchecker.com/api/v1/crawls/clz9h8m4c0002ijkl5678mnop/export/links \
  -H "x-api-key: sk_your_key" \
  -o links.csv

One row per affiliate link found on the crawl, with the columns page, link, network, tag, issues, outcome. Only rows the resolve step has finished are returned, so the file carries the same rows the report shows. The only export kind is links, so another kind is 404, like a crawl that is not there.

Errors

Errors are JSON with two fields: error, a label a client can branch on, and message, the sentence a person can read.

{
  "error": "Unauthorized.",
  "message": "Send a valid API key as Authorization: Bearer <key> or in the x-api-key header."
}