A deterministic yes or no for whether a PyPI or npm package name is real, answered from published artifacts. On a miss, you also learn which real names sit within edit distance 2. That is the typosquat signal.
The answer comes from the artifact we ingested, not from registry search rankings and not from model memory. 686 packages and 645,969 symbols indexed today, growing on demand.
PyPI wheels and npm tarballs, downloaded and parsed. The same name always gets the
same answer, and latest_version echoes the release the proof covers.
On a miss, typosquat_adjacent is true when a real package sits within
edit distance 2, and adjacent_to names it. "requestz" flags "requests".
Positive answers carry proof.artifact_sha256 and source_url
for the exact wheel or tarball indexed, plus an EIP-191 attestation verifiable free at
/receipts/verify.
Same pipeline as the paid route, 25 calls a day per client IP across the four demo endpoints. This is the exact request:
curl -X POST https://attester.dev/demo/v1/package/exists \ -H 'Content-Type: application/json' \ -d '{"ecosystem": "pypi", "name": "requests"}'
# 200 OK (trimmed) { "exists": true, "latest_version": "2.34.2", "typosquat_adjacent": false, "adjacent_to": [], "source": "ingested", "proof": { "source_url": "https://pypi.org/project/requests/", "artifact_sha256": "2a0d60c1…" }, "attestation": { "verdict": "exists", "…": "…" }, "attestation_hash": "0x…", "signature": "0x…", "served_in_ms": 10 }
A miss returns "exists": false
with latest_version: null and, when a real name is close,
typosquat_adjacent: true with adjacent_to filled. Request body:
{"ecosystem": "pypi" | "npm", "name": str}.
The demo route is free: 25 calls per day per client IP, no headers, reset 00:00 UTC, HTTP 429 when spent. The paid route is POST /v1/package/exists at $0.002 per call, payable per call with x402 (USDC on Base) or with prepaid credits (X-API-Key from the Stripe pack). Names we have not indexed yet are ingested on the spot when the registry has them, bounded per request. A miss on a private package means "not on the public registry", which is the correct answer for import checks.
Full request and payment details in /llms.txt. Charge and refund rules in /policy.