URL Resolver API

Where does this link actually go, and who gets paid when I click it

The URL Resolver API follows and analyzes links as clean JSON.

no credit card1,000 free credits · instant API key · live in 10 seconds
Missing a URL Resolver endpoint, or need a source we don't have yet?Contact us real people · same-day reply.
U
/url-resolver/v1

8 active endpoints. Every call is 1 credit.

  • POST/url-resolver/v1/resolve
  • POST/url-resolver/v1/normalize
  • POST/url-resolver/v1/detect_affiliate
  • POST/url-resolver/v1/product_hint
  • POST/url-resolver/v1/preview
  • POST/url-resolver/v1/safety
  • POST/url-resolver/v1/full
  • +1 more

What URL Resolver endpoints does ReefAPI ship?

8 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.

8 endpoints

resolve

1 cr

Follow the redirect chain to the final URL (hop-by-hop, every status observable).

required
url
optional
max_hops

normalize

1 cr

Resolve then strip tracking params (utm_*/fbclid/gclid…) → canonical URL.

required
url
optional
follow

detect_affiliate

1 cr

Detect the affiliate network/params/merchant across the whole redirect chain, incl.

required
url
optional
follow

product_hint

1 cr

Identify marketplace + product-id + the ReefAPI engine that can fetch the product.

required
url
optional
follow

preview

1 cr

Link unfurl.

required
url
optional

safety

1 cr

Heuristic URL-risk flags (ip-host, non-https, punycode, userinfo, high-abuse TLD, long/multi-…

required
url
optional

full

1 cr

One call.

required
url
optional
max_hops

batch

1 cr

Resolve up to 50 URLs concurrently in one call.

required
urls
optional

Every parameter, every allowed value →

URL Resolver API

3 of 8 endpoints, ready to run

View docs ↗

The whole answer in one call: every hop with its status code and resolved IPs, the final URL, the canonical and cleaned forms, the tracking parameters removed, the affiliate verdict and the link preview.

1 credit1 required · 1 optional
POST/url-resolver/v1/full
ok18706 ms · 1 records · sample
{
  "ok": true,
  "meta": {
    "api": "url-resolver",
    "endpoint": "full",
    "mode": "live",
    "latency_ms": 18705.9,
    "record_count": 1,
    "cache_hit": false
  },
  "data": {
    "input_url": "https://amzn.to/3QZmYbT",
    "final_url": "https://www.amazon.com/",
    "final_domain": "www.amazon.com",
    "redirect_chain": [
      {
        "url": "https://amzn.to/3QZmYbT",
        "status": 302,
        "resolved_ips": [
          "67.199.248.12",
          "67.199.248.13"
        ],
        "content_type": "text/html; charset=utf-8",
        "location": "http://www.amazon.com"
      },
      {
        "url": "http://www.amazon.com",
        "status": 301,
        "resolved_ips": [
          "13.33.52.208",
          "2600:9000:2130:5400:7:49a5:5fd6:da1",
          "2600:9000:213f:7e00:7:49a5:5fd6:da1"
        ],
        "content_type": "text/html",
        "location": "https://www.amazon.com/"
      },
      {
        "url": "https://www.amazon.com/",
        "status": 202,
        "resolved_ips": [
          "13.33.52.208",
          "2600:9000:2130:5400:7:49a5:5fd6:da1",
          "2600:9000:213f:7e00:7:49a5:5fd6:da1"
        ],
        "content_type": "text/html; charset=UTF-8"
      }
    ],
    "status_codes": [
      302,
      301,
      202
    ],
    "hop_count": 2,
    "content_type": "text/html; charset=UTF-8",
    "is_short_link": true,
    "redirect_loop": false,
    "final_blocked": false,
    "stop_reason": "complete",
    "canonical_url": "https://www.amazon.com/",
    "cleaned_url": "https://www.amazon.com/",
    "stripped_tracking_params": [],
    "detected_platform": "amazon",
    "page_title": "",
    "affiliate": {
      "is_affiliate": true,
      "affiliate_type": "network",
      "affiliate_network": "amazon_associates",
      "affiliate_params": {},
      "merchant_hint": "amazon",
      "all_networks": [
        {
          "network": "amazon_associates",
          "params": {},
          "via": "amzn.to"
        }
      ],
      "first_party_signals": []
    },
    "product": {
      "final_domain": "www.amazon.com",
      "marketplace": "amazon",
      "possible_product_id": null,
      "engine_hint": "amazon",
      "is_product_url": false
    },
    "preview": {
      "title": "",
      "description": null,
      "image": null,
      "site_name": null,
      "type": null,
      "card": null,
      "favicon": null,
      "has_opengraph": false
    },
    "safety": {
      "risk_level": "none",
      "risk_score": 0,
      "flags": [],
      "domain_changed": true,
      "final_is_https": true,
      "threat_intel": {
        "provider": "urlhaus",
        "status": "phase2_needs_auth_key",
        "note": "heuristic risk flags only — NOT a malware DB. Real malware/phishing intel (abuse.ch URLhaus / Google Safe Browsing) needs an Auth-Key (URLhaus returns 401 without one); Phase-2 flag, like a PSI key"
      }
    }
  }
}
Real response, fetched from the live endpoint with the parameters on the left — trimmed to the first few rows, with seller names left out. Press Try it for the untrimmed response.

How the URL Resolver API works

URL Resolver is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.

01
Authenticate
x-api-key header

No OAuth app, no request signing, no per-site account. One key covers all 184 engines.

02
Call
POST /url-resolver/v1/…

Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.

03
Pay
1 credit per call

Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.

04
Read
{ ok, data, meta, error }

One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.

De-duplicating a table of links that are secretly the same page

A campaign table, a scraped feed and a shared inbox will all contain the same product page five times, each with different tracking. String comparison sees five rows.

01full
POST/url-resolver/v1/full
{"url": "https://amzn.to/3QZmYbT"}

Returns the destination plus cleaned_url with the tracking parameters stripped and stripped_tracking_params naming each one.

02Group your rows on cleaned_url instead of the raw link.
POSTGroup your rows on cleaned_url instead of the raw link.

The chain is returned too, so a row that changed domain on the way is visible rather than silently merged.

One credit per link turns five rows into one, and the parameters you removed are on the record — which matters when someone later asks why two campaigns collapsed into one.

request
curl -X POST https://api.reefapi.com/url-resolver/v1/full \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://www.amazon.com/dp/B08N5WRWNW?tag=aff-20&utm_source=x"}'
response envelope
{
  "ok": true,
  "data": { … },
  "meta": {
    "api": "url-resolver",
    "endpoint": "full",
    "mode": "live",
    "latency_ms": …,
    "record_count": …
  },
  "error": null
}

What each block gives you, with measured output

Seven actions read one URL from different angles, and full returns every block in a single call. The examples are two measured runs: a bit.ly short link, and an Amazon product URL carrying both an affiliate tag and a UTM parameter.

ActionKey fieldsMeasured output
resolvefinal_url, redirect_chain[] (url, status, host, resolved_ips), status_codes[], hop_count, is_short_link, redirect_loop, stop_reasonthe bit.ly link: hop_count 0, status 200, is_short_link true, stop_reason "complete"
normalizecanonical_url, cleaned_url, stripped_tracking_params[], detected_platform, page_titlestripped_tracking_params ["utm_source"] — and tag=test-20 deliberately kept
detect_affiliateis_affiliate, affiliate_type, affiliate_network, affiliate_params, merchant_hint, all_networks[]network "amazon_associates", params {tag: "test-20"}, merchant_hint "amazon"
product_hintmarketplace, possible_product_id, engine_hint, is_product_urlmarketplace "amazon", possible_product_id "B08N5WRWNW", engine_hint "amazon"
previewtitle, description, image, site_name, type, card, favicon, has_opengraphtitle from the page; has_opengraph false when the page publishes no OG tags
safetyrisk_level, risk_score, flags[], domain_changed, final_is_https, threat_intela plain http:// URL scored 22, risk_level "low", flags ["non_https_final"]
full / batchevery block merged / one resolve block per URLuse full for one link, batch for a list

engine_hint is the useful part of product_hint: it names the ReefAPI engine that can fetch that product, so an unknown link becomes a routed call without you writing a domain-to-engine map. Measured, an Amazon URL returned engine_hint "amazon".

What a redirect chain can and cannot promise

Measured on a real short link, a tracking-laden URL, an affiliate link and a stale bit.ly. Two of these are worth knowing before you trust the output.

Every hop is returned, with the IPs it resolved to

Not just the final URL — each hop carries its status code, its host, its content type and the addresses that host resolved to at the time of the call. A chain that quietly changes domain is visible in the record rather than collapsed into a single answer, and the loop and stop-reason flags say why it ended.

Tracking removal is named, not just done

A URL carrying utm_source, utm_medium, gclid and a real id came back with the three tracking parameters listed by name and id kept. That list is the difference between a cleaner you can audit and one you have to trust — and canonical_source tells you whether the clean form came from the page's own canonical tag or from the strip.

Affiliate detection names the network and the parameter

An Amazon link with a tag came back as an affiliate link of type network, with the network identified, the tag parameter and its value extracted, and the merchant named. It also reports first-party signals separately from network ones, so a merchant's own campaign parameter is not miscounted as somebody's commission.

Against us: a short link is a promise, not a destination

An expired Amazon short link resolved to the Amazon home page rather than to a product, and an old bit.ly resolved to an entirely unrelated site. Both are correct answers — the link really does go there now. What a resolver cannot tell you is what the link meant when it was created, so treat the destination as current fact, not as evidence about the past.

Against us: preview text comes back in the language the site serves us

The resolver asks for pages with a Turkish language preference, because that is what keeps Turkish merchant short-links on their own storefront instead of bouncing to an app-store page. On sites that localise by that header, the preview title and description come back in Turkish rather than English. The structural fields — URL, chain, parameters, affiliate verdict — are unaffected; it is the human-readable preview text that carries the locale.

The safety score is a heuristic, and says so

The risk endpoint returns a level, a numeric score and the individual flags that produced it — domain changed on the way, destination not on HTTPS — alongside a threat-intelligence block that reports its own status. It is a set of stated signals you can weigh, not a verdict handed down.

What people build with URL Resolver

The jobs this data is most often used for.

8

endpoints

1

credit per call

01

Affiliate tools call detect_affiliate to identify and handle monetized links.

02

Moderation uses safety to screen a shortened link before allowing it.

03

Commerce uses product_hint to map a redirect to a product.

What URL Resolver data costs

The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.

Full pricing →
$0.67–$1.50 / 1,000 credits
  • 1,000 free credits on signup, no card
  • One key, all 184 APIs, one credit pool
  • Failed and blocked calls are never charged
  • Credits roll over and never expire

Call it in two lines

Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.

curl
curl -X POST https://api.reefapi.com/url-resolver/v1/full \
  -H "x-api-key: $REEF_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://www.amazon.com/dp/B08N5WRWNW?tag=aff-20&utm_source=x"}'
python
import requests

r = requests.post(
    "https://api.reefapi.com/url-resolver/v1/full",
    headers={"x-api-key": REEF_KEY},
    json={
  "url": "https://www.amazon.com/dp/B08N5WRWNW?tag=aff-20&utm_source=x"
},
)
print(r.json()["data"])
FAQ

Have a question? We got answers.

The questions people actually ask before wiring up URL Resolver.

Get a free key →
Why does cleaned_url still contain the affiliate tag?

Because cleaning removes analytics parameters, not attribution. Measured on an Amazon URL carrying both, stripped_tracking_params came back as ["utm_source"] while tag=test-20 survived into both canonical_url and cleaned_url. That is deliberate: silently deleting an affiliate tag would break someone's revenue attribution without telling them. If you want a genuinely bare URL, take the keys listed in affiliate.affiliate_params and remove them yourself — the response names them precisely so you can.

Is the safety block a malware or phishing check?

No, and it says so rather than implying otherwise. threat_intel returns status "phase2_needs_auth_key" with a note stating these are heuristic risk flags and not a malware database — real intelligence from abuse.ch URLhaus or Google Safe Browsing needs a key we do not ship. What you do get is honest structural signal: risk_score, flags such as non_https_final, domain_changed telling you the final host differs from the one you were given, and final_is_https. A measured plain-http URL scored 22 with one flag. Use it to triage, never as a security verdict.

A short link came back with status 200 — does that mean it resolved?

Not necessarily. A measured call on a bit.ly path that does not exist returned status 200, hop_count 0, final_url identical to the input and final_domain still bit.ly — the shortener served its own page rather than redirecting. Check hop_count and whether final_domain changed, not just the status code. is_short_link true combined with hop_count 0 is the signature of a dead or invalid short link.

Where does possible_product_id come from — the page or the URL?

The URL pattern, which is why it still works when the page does not. A measured Amazon link returned status 404 and page_title "Page Not Found", yet product_hint still extracted possible_product_id "B08N5WRWNW" and set is_product_url true, because the /dp/<ASIN>/ shape is unambiguous. That is useful — you can classify a link without a successful fetch — but it means the id is a well-formed candidate, not proof the product exists. Confirm it with the engine named in engine_hint.

What is in redirect_chain beyond the URLs?

Each hop carries its own url, HTTP status, host, content_type and resolved_ips, and that IP list includes IPv6 where the host publishes it — a measured hop returned six addresses across both families. status_codes[] is the same sequence flattened, which is what you want for a quick 301-versus-302 check. hop_count is the number of redirects, so zero means the URL you passed was already final. max_hops caps how far it will follow, and redirect_loop plus stop_reason tell you why it stopped.

How do I tell a first-party affiliate link from a network one?

affiliate_type separates them: "network" means a recognized affiliate network with named parameters, and "first_party" means the merchant's own referral scheme, reported through first_party_signals. all_networks[] handles the case where a chain passes through more than one, recording which host each was seen on. A measured Amazon Associates link returned affiliate_type "network", affiliate_network "amazon_associates" and a single entry in all_networks tagged with the host it came from.

Should I call full or the individual actions?

full when you have one link and want everything, because it merges resolve, normalize, affiliate, product, preview and safety into one response and one round trip. The individual actions are for volume: preview and safety both fetch the page, so calling them separately on a large list costs more than it needs to. batch is the third option, returning one resolve block per URL with its own ok flag plus count and ok_count, which is the right shape for cleaning a link table.

What is the URL Resolver API?

URL Resolver API is a ReefAPI endpoint group for url resolver It returns live JSON through POST requests under /url-resolver/v1.

Is the URL Resolver API free to try?

Yes. ReefAPI starts with 1,000 free credits, no card required. URL Resolver calls use the same shared credit balance as every other ReefAPI engine.

Do I need an URL Resolver login or account?

No login to URL Resolver is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.

How fresh is the URL Resolver data?

The page example is captured from a live resolve call, and production requests fetch live data through ReefAPI rather than a static sample.

How many credits does the URL Resolver API use?

URL Resolver actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.

Can I call URL Resolver from an AI assistant or MCP client?

Yes. Connect ReefAPI once through MCP and your assistant can call url-resolver actions with the same key, credit pool and JSON envelope used by normal REST requests.

Is the URL Resolver API an URL Resolver scraper?

It is the managed alternative to a DIY URL Resolver scraper. Instead of building and maintaining your own scraper — proxies, headless browsers, captcha and constant breakage — you call one ReefAPI endpoint and get the same url resolver back as clean JSON.

19 Utilities & AI APIs on the same key

One key, one credit pool, one response envelope. If you are pulling URL Resolver, you are one call away from the rest of the category — no second contract, no second integration.

Need something this API does not do?

Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.

0/4000

No account needed · we reply from [email protected]

Try it on your own data before you pay anything

The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.

Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.