linkspect API docs linkspect.com

Getting started

The linkspect API tells you whether a URL opens for subscribers of particular operators in particular countries, on home broadband and on mobile. When it does not open, the result says where it stopped (DNS, IP, TLS, HTTP) and keeps that apart from failures of our own measuring point.

Everything is JSON over HTTPS. The base URL is https://api.linkspect.com/v1.

1. Get a key

Keys are handed out by hand for now. Ask for one at linkspect.com/request-access. You get two kinds:

Send the key in every request as a bearer token:

Authorization: Bearer lsk_test_…

A request without a key, or with a wrong one, gets 401.

2. Run your first check

With a test key, check a host name that the fixture engine reports as blocked in DNS at Deutsche Telekom (home broadband):

curl https://api.linkspect.com/v1/checks \
  -H "Authorization: Bearer $LINKSPECT_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=10" \
  -d '{
    "url": "https://blocked-dns.fixtures.linkspect.com/",
    "targets": [
      {"country": "DE", "operator": "de-telekom", "connection_type": "fixed"}
    ]
  }'

What the fields mean:

Prefer: wait=10 asks the API to hold the request for up to 10 seconds. A quick fixture check finishes in about 2, so the answer is 201 with all results. Without Prefer you get 202 right away and fetch the result later; see Waiting and polling.

To see which cohorts a check would have and what it would cost before running it, send the same body to POST /v1/checks:preview. It starts nothing and charges nothing.

3. Read the answer

The response, shortened:

{
  "id": "chk_01M70352F0PPK2KK6JCW2W0B44",
  "status": "completed",
  "test": true,
  "summary": {
    "verdicts": {"ok": 0, "blocked": 1, "target_down": 0, "target_policy": 0},
    "non_verdicts": {"provider_policy": 0, "exit_regime": 0, "proxy_failure": 0,
                     "inconclusive": 0, "not_measured": 0},
    "blocked_at": [{"country": "DE", "operator": {"id": "de-telekom", "name": "Telekom", "asn": 3320},
                    "connection_type": "fixed"}],
    "pending": 0
  },
  "cohorts": [{
    "country": "DE",
    "operator": {"id": "de-telekom", "name": "Telekom", "asn": 3320},
    "connection_type": "fixed",
    "status": "completed",
    "final": true,
    "result": {
      "outcome": "blocked",
      "verdict": true,
      "layer": "dns",
      "method": "redirect",
      "confidence": "likely",
      "uncalibrated": true,
      "coverage": {"checked": ["dns"], "unchecked": ["ip", "tcp", "tls", "http", "quic", "ech"]},
      "coverage_gaps": [],
      "evidence": {"subscribers": 3, "subnets": 2, "pools": 1, "measurements_used": 3, "excluded": [], …},
      "explanation": {"language": "en", "text": "Test key: this result comes from the fixture engine. …", …},
      "populations": [],
      "versions": {"engine": "fixtures-0.1.0", "rules": "0.1.0", "calibration": "none",
                   "geo_pack": "DE@0.1.0", "geo_pack_status": "shadow"}
    }
  }],
  "user_filters": []
}

Read it from the top:

A blocked or unreachable site is a normal successful response with an outcome. Errors (4xx, 5xx) only mean the request itself could not be handled; see Errors.

The next page, Reading results, goes through every part of a result: all nine outcomes, yellow ok, populations and the checks outside the operator's network in user_filters, including real browsers.

What else to know