AnvilJSON utilities

Anvil › Docs › /v1/url/inspect

Link checker API: find who really owns a URL and spot phishing tricks

The only part of a web address that says who owns it is the name just before the public ending: bbc.co.uk, example.com, someone.github.io. Everything in front is decoration the owner chose. This endpoint finds that owner for you and lists the tricks a link uses to hide it, each with a severity and a plain-words explanation.

In one line: GET /v1/url/inspect?url=http%3A//paypal.com.secure-login.top/verify%3Fnext%3Dhttps%3A//example.net/ returns JSON. No key, CORS on, 60 requests a minute.
GET

/v1/url/inspect

Link X-ray: who really owns a link, and its warning signs. Change the values and press Send request to call the live API.

Parameters

NameTypeWhat it doesDefault
url requiredstringThe link to inspect, up to 2 KB. It is never opened.—

Example

Request:

GET https://api.oddlathe.com/v1/url/inspect?url=http%3A//paypal.com.secure-login.top/verify%3Fnext%3Dhttps%3A//example.net/

Response (generated by the real code when these docs were last built):

{
 "input": "http://paypal.com.secure-login.top/verify?next=https://example.net/",
 "assumed_scheme": false,
 "scheme": "http",
 "host": "paypal.com.secure-login.top",
 "host_unicode": "paypal.com.secure-login.top",
 "owner": "secure-login.top",
 "owner_unicode": "secure-login.top",
 "public_suffix": "top",
 "suffix_type": "icann",
 "subdomain": "paypal.com",
 "ip": false,
 "port": null,
 "path": "/verify",
 "query": [
  [
   "next",
   "https://example.net/"
  ]
 ],
 "fragment": null,
 "passes_you_to": [
  {
   "param": "next",
   "owner": "example.net"
  }
 ],
 "warning_level": "high",
 "flags": [
  {
   "code": "dressed_up",
   "severity": "warn",
   "message": "Something official-looking is placed in front (paypal.com), but the owner is the part at the end: secure-login.top."
  },
  {
   "code": "bait_words",
 …

Code examples

curl
curl -G 'https://api.oddlathe.com/v1/url/inspect' \
  --data-urlencode 'url=http://paypal.com.secure-login.top/verify?next=https://example.net/'
JavaScript (browser or Node 18+)
const params = new URLSearchParams({
  url: "http://paypal.com.secure-login.top/verify?next=https://example.net/"
});
const res = await fetch(`https://api.oddlathe.com/v1/url/inspect?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);
Python (standard library only)
import json, urllib.parse, urllib.request

params = urllib.parse.urlencode({"url": "http://paypal.com.secure-login.top/verify?next=https://example.net/"})
url = "https://api.oddlathe.com/v1/url/inspect?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
    data = json.load(r)
print(data)

When it's useful

  • Showing "you're about to visit <b>owner</b>" before following a user-submitted link in your app or chat
  • Flagging suspicious links in a support inbox, moderation queue or teaching tool
  • Grouping URLs by site (the right way, so <code>a.co.uk</code> and <code>b.co.uk</code> aren't the same owner)
  • Teaching people how to read a link

Good to know

  • owner is the ASCII (punycode) form and owner_unicode the readable one. suffix_type is private for platforms where anyone can make a site (github.io, blogspot.com, pages.dev…), and a shared_platform flag explains what that means.
  • warning_level is none, low, medium or high. Each item in flags has a code, a severity (info, warn, danger) and a message you can show to people as it is.
  • Codes you may see: at_sign, disguised_ip, ip_address, lookalike_letters (with looks_like), international_name, digit_lookalike, letter_pairs, dressed_up, bait_words, deep_subdomain, cheap_ending, shortener, no_https, unusual_port, redirect_param (with passes_you_to), program_download, double_extension, encoded_host, script_link, data_link.
  • Nothing is fetched, so shortened links can't be expanded and a clean result is not a safety guarantee. Links without a scheme are read as https:// and marked assumed_scheme. Remember to URL-encode the link you pass in.
  • Want to learn to spot these by eye? The fake-message lesson on Wirebook has a pretend inbox and the same X-ray as a toy.

Finds the registrable domain (the real owner) with the full Public Suffix List, decodes international names, and lists warning signs with a severity: @ tricks, disguised IP addresses, look-alike letters from other alphabets, digits for letters, official words dressed up in front, redirect parameters, double file endings and more. Pure text analysis: the link is never fetched, resolved or stored.

Errors

Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:

  • missing_param (400): a required parameter is missing or empty
  • bad_param (400): a value is the wrong type or out of range (the message says which)
  • rate_limited (429): over 60 requests a minute; wait for Retry-After seconds

Questions

Which part of a link shows who owns it?

Read the site name from the right: skip the public ending (.com, .co.uk) and the word just before it is the owner. In <code>paypal.com.secure-login.top</code> the owner is <code>secure-login.top</code>.

Why use the Public Suffix List?

Because endings aren't always one word. <code>co.uk</code>, <code>com.au</code> and platforms like <code>github.io</code> are shared endings, so taking the last two words of the name gets the owner wrong.

Can it tell me a link is safe?

No. It reads the text only and never visits the page. A link with no warning signs can still lead somewhere bad; it's one helpful check, not a verdict.

Related endpoints

Prefer a page to an API?

Published · OpenAPI 3.1 spec · Limits and privacy