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"}
]
}'
url: the full URL, path and query included.httpson port 443 for any domain.targets: a country, optionally narrowed byoperator(catalog ID such asde-telekom, or an AS number such asAS3320) andconnection_type(fixedormobile). Each target expands into cohorts.check_type:availability(default). Not available yet (being built):content, which also checks for an expected text on the page ("content": {"expect": "Pay now", "mode": "present"}).profile:quick, usually done within a minute.
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:
| Host | Result |
|---|---|
blocked-dns.fixtures.linkspect.com | blocked, dns.redirect |
blocked-sni.fixtures.linkspect.com | blocked, tls_sni |
target-down.fixtures.linkspect.com | target_down |
proxy-failure.fixtures.linkspect.com | proxy_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
- Errors are
application/problem+json(RFC 9457). Thetypeis a stable address you can switch on: list of error types. Idempotency-Keymakes retries safe for 24 hours: the same key and body return the original check.- Rate limits are reported in
RateLimitandRateLimit-Policyheaders; on429, waitRetry-Afterseconds.
Ask for the full API reference when you request a key. Get early access