Get access

API quickstart

One endpoint creates a check, one returns it. Everything is JSON over HTTPS at https://api.linkspect.com/v1.

Authentication

Send your key as a bearer token: Authorization: Bearer lsk_live_…. Live keys measure through real subscriber connections. Test keys (lsk_test_…) run against a fixture engine instead of real connections and are never charged: use them to build your integration.

Create a check

curl https://api.linkspect.com/v1/checks \
  -H "Authorization: Bearer $LINKSPECT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7f2c4a1e-checkout-de" \
  -H "Prefer: wait=30" \
  -d '{
    "url": "https://shop.example/checkout/?step=pay",
    "targets": [
      {"country": "DE"},
      {"country": "PL", "operator": "pl-plus"}
    ]
  }'

Without Prefer the API answers 202 Accepted at once, with a Location header. With Prefer: wait=N (up to 30 seconds) it answers 201 if everything finished in time, or 202 with the current state. Then poll:

curl https://api.linkspect.com/v1/checks/chk_01M7014ZP0... \
  -H "Authorization: Bearer $LINKSPECT_KEY"

A cohort with "final": true will not change any more. Under load, a full check of all main cohorts in Germany, Poland and Norway finished in 35 seconds at the median and 62 seconds at the 95th percentile in our last load test.

Read the result

Abridged response with made-up data. A blocked site is a normal 2xx answer with an outcome; errors are only for requests that are themselves wrong.

{
  "id": "chk_01M7014ZP0MDASRYY7SY46YDGW",
  "status": "completed",
  "check_type": "availability",
  "profile": "quick",
  "summary": {
    "verdicts":     {"ok": 5, "blocked": 1, "target_down": 0, "target_policy": 0},
    "non_verdicts": {"provider_policy": 0, "exit_regime": 0, "proxy_failure": 1,
                     "inconclusive": 0, "not_measured": 0}
  },
  "cohorts": [
    {
      "country": "DE",
      "operator": {"id": "de-telekom", "name": "Telekom", "asn": 3320},
      "connection_type": "fixed",
      "final": true,
      "result": {
        "outcome": "blocked",
        "verdict": true,
        "layer": "dns",
        "method": "redirect",
        "confidence": "confirmed",
        "uncalibrated": true,
        "coverage_gaps": [],
        "evidence": {"subscribers": 3, "subnets": 2, "pools": 1},
        "explanation": {
          "language": "en",
          "text": "Telekom's DNS points the name to a notice page for 3 subscribers in 2 subnets. Subscribers who use Cloudflare DNS open the site."
        },
        "populations": [
          {"group": "isp_default", "outcome": "blocked", "layer": "dns", "method": "redirect"},
          {"group": "public:cloudflare", "outcome": "ok"}
        ]
      }
    }
  ],
  "user_filters": [
    {"kind": "public_dns", "service": "cloudflare", "mode": "family",
     "verdict": "blocked", "signal": "0.0.0.0"}
  ]
}

Every result links to its measurements (GET /v1/measurements/{id}): the exit's network and subnet, the DNS answer, the certificate, the HTTP status, timings. Exits are described by network number, country and connection type, never by IP address. Explanations come in English or Russian (Accept-Language).

Test keys and fixtures

With a test key, any URL gives ok in every cohort, except these host names, which always produce the named result:

HostResult
blocked-dns.fixtures.linkspect.comblocked, dns.redirect
blocked-sni.fixtures.linkspect.comblocked, tls_sni
target-down.fixtures.linkspect.comtarget_down
proxy-failure.fixtures.linkspect.comproxy_failure

Other endpoints

POST /v1/checks:preview
Which cohorts a request would create, how measurable each one is today and what it would cost. Free.
GET /v1/checks
Your checks, newest first, with cursor pagination.
POST /v1/checks/{id}:cancel
Stop a running check. Cancelled cohorts are not charged.
GET /v1/geos
Countries, operators, network numbers and connection types.
GET /v1/geos/{country}
One country in detail: providers, connection types and what can be measured there today.
GET /v1/measurements/{id}
The raw evidence behind a result.

Errors, retries, limits

Ask for the full API reference when you request a key. Get early access