POST/v1/phishing/url-expand

URL Expand

Follow a URL through its entire redirect chain to reveal the final destination. Useful for unshortening links and detecting suspicious multi-hop redirects often used in phishing campaigns.

Try this endpoint in the playground →

Credits

1

Per request

Max Hops

10

5s per hop; 20s total

Plans

All

Free, Starter, Professional, Enterprise

Behavior & Security

FeatureDetail
Max redirects10 hops — returns an error if exceeded
Timeout per hop5 seconds — a timeout means the chain is incomplete
SSRF protectionRedirects to private/internal IPs (RFC 1918, loopback, link-local) are blocked
Suspicious flagChains with more than 3 hops or SSRF-blocked hops are automatically marked suspicious
Completionstatus is complete, partial, or failed; errorCode identifies incomplete HTTP HEAD chains
Hop detailsEach hop reports the status code, server header, and location header

SSRF protection validates destinations before following HTTP redirects. A prohibited destination terminates the chain with an error. Check hop errors, timeouts, and loop detection before treating expansion as complete. A complete status only means the HTTP HEAD chain ended successfully. This does not assess whether page content is malicious, and does not follow JavaScript or HTML meta-refresh navigation. Expanding a URL actively contacts its destination and may notify its sender.

Request Body

FieldTypeRequiredDescription
urlstringYesThe URL to expand (follow redirects). Max 2048 characters, must use http:// or https://, must not contain embedded credentials.

Code Examples

cURL

curl -X POST https://api.dfir-lab.ch/v1/phishing/url-expand \
  -H "Authorization: Bearer sk-dfir-your-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://bit.ly/3xYzAbC"
  }'

Python

import requests

response = requests.post(
    "https://api.dfir-lab.ch/v1/phishing/url-expand",
    headers={
        "Authorization": "Bearer sk-dfir-your-key-here",
        "Content-Type": "application/json",
    },
    json={
        "url": "https://bit.ly/3xYzAbC"
    },
)

result = response.json()
data = result["data"]
meta = result["meta"]
print(f"Final URL: {data['finalUrl']}")
print(f"Hops: {data['hopCount']}")
print(f"Suspicious: {data['suspicious']}")
print(f"Credits remaining: {meta['credits_remaining']}")

for i, hop in enumerate(data["hops"], 1):
    print(f"  {i}. [{hop['statusCode']}] {hop['url']}")

Example Response

Standard redirect chain (not suspicious)

{
  "data": {
    "originalUrl": "https://bit.ly/3xYzAbC",
    "finalUrl": "https://www.example.com/landing-page?ref=campaign",
    "hopCount": 2,
    "suspicious": false,
    "redirectLoop": false,
    "status": "complete",
    "errorCode": null,
    "hops": [
      {
        "url": "https://bit.ly/3xYzAbC",
        "statusCode": 301,
        "server": "bit.ly",
        "location": "https://www.example.com/landing-page?ref=campaign"
      },
      {
        "url": "https://www.example.com/landing-page?ref=campaign",
        "statusCode": 200,
        "server": "nginx",
        "location": null
      }
    ]
  },
  "meta": {
    "request_id": "req_a1b2c3d4-...",
    "credits_used": 1,
    "credits_remaining": 486,
    "processing_time_ms": 823
  }
}

Suspicious redirect chain (>3 hops)

{
  "data": {
    "originalUrl": "https://t.co/aB1cD2eF3g",
    "finalUrl": "https://phishing-site.example.com/login",
    "hopCount": 5,
    "suspicious": true,
    "redirectLoop": false,
    "status": "complete",
    "errorCode": null,
    "hops": [
      {
        "url": "https://t.co/aB1cD2eF3g",
        "statusCode": 301,
        "server": "tsa_b",
        "location": "https://shortener2.example.com/r/abc123"
      },
      {
        "url": "https://shortener2.example.com/r/abc123",
        "statusCode": 302,
        "server": "cloudflare",
        "location": "https://redirect3.example.net/go?u=xyz"
      },
      {
        "url": "https://redirect3.example.net/go?u=xyz",
        "statusCode": 302,
        "server": "Apache/2.4",
        "location": "https://tracker.example.org/click?id=9876"
      },
      {
        "url": "https://tracker.example.org/click?id=9876",
        "statusCode": 301,
        "server": "openresty",
        "location": "https://phishing-site.example.com/login"
      },
      {
        "url": "https://phishing-site.example.com/login",
        "statusCode": 200,
        "server": "nginx",
        "location": null
      }
    ]
  },
  "meta": {
    "request_id": "req_e5f6g7h8-...",
    "credits_used": 1,
    "credits_remaining": 485,
    "processing_time_ms": 2147
  }
}