DEV Community

Alex Spinov
Alex Spinov

Posted on

AlienVault OTX Has a Free API — Threat Intelligence From 200,000+ Contributors

AlienVault Open Threat Exchange (OTX) is the world's largest open threat intelligence community. 200,000+ contributors sharing indicators of compromise (IOCs) in real-time.

Their API is completely free. No usage limits. No premium tier needed.

The Problem It Solves

Threat intelligence feeds are expensive. CrowdStrike, Recorded Future, ThreatConnect — they charge thousands per year. Small security teams can't afford them.

OTX gives you the same type of data: malicious IPs, domains, file hashes, URLs — crowdsourced from 200K+ security researchers worldwide. For free.

Get Your Free API Key

  1. Sign up at otx.alienvault.com
  2. Go to Settings → API Integration
  3. Copy your OTX API Key

Check an IP for Threats

\`python
import requests

API_KEY = "your-otx-api-key"
headers = {"X-OTX-API-KEY": API_KEY}
BASE = "https://otx.alienvault.com/api/v1"

def check_ip(ip):
"""Get threat intelligence for an IP address."""

# General info
r = requests.get(f"{BASE}/indicators/IPv4/{ip}/general", headers=headers, timeout=15)
data = r.json()

pulse_count = data.get("pulse_info", {}).get("count", 0)
country = data.get("country_name", "Unknown")

print(f"IP: {ip}")
print(f"Country: {country}")
print(f"Threat pulses: {pulse_count}")

if pulse_count > 0:
    print("⚠ This IP appears in threat intelligence feeds:")
    for pulse in data["pulse_info"].get("pulses", [])[:3]:
        print(f"  └─ {pulse['name']} ({pulse['created']})")
        print(f"     Tags: {', '.join(pulse.get('tags', [])[:5])}")
else:
    print("✓ No known threat associations")

# Reputation
r2 = requests.get(f"{BASE}/indicators/IPv4/{ip}/reputation", headers=headers, timeout=15)
rep = r2.json().get("reputation", {})
if rep:
    print(f"Reputation: {rep.get('threat_score', 'N/A')}/7")
Enter fullscreen mode Exit fullscreen mode

check_ip("185.220.101.1")
`\

Check a Domain

\`python
def check_domain(domain):
"""Get threat intelligence for a domain."""

r = requests.get(f"{BASE}/indicators/domain/{domain}/general", headers=headers, timeout=15)
data = r.json()

pulses = data.get("pulse_info", {}).get("count", 0)

print(f"Domain: {domain}")
print(f"Threat pulses: {pulses}")

# Get passive DNS
r2 = requests.get(f"{BASE}/indicators/domain/{domain}/passive_dns", headers=headers, timeout=15)
dns_data = r2.json().get("passive_dns", [])

if dns_data:
    print(f"DNS records: {len(dns_data)}")
    for record in dns_data[:5]:
        print(f"  {record.get('address', '?')} — {record.get('record_type', '?')} (seen: {record.get('last', '?')})")
Enter fullscreen mode Exit fullscreen mode

check_domain("example.com")
`\

Check a File Hash

\`python
def check_hash(file_hash):
"""Check if a file hash is associated with malware."""

r = requests.get(f"{BASE}/indicators/file/{file_hash}/general", headers=headers, timeout=15)
data = r.json()

pulses = data.get("pulse_info", {}).get("count", 0)

print(f"Hash: {file_hash[:32]}...")
print(f"Threat pulses: {pulses}")

if pulses > 0:
    print("⚠ Known malicious file:")
    for p in data["pulse_info"].get("pulses", [])[:3]:
        print(f"  └─ {p['name']}")
Enter fullscreen mode Exit fullscreen mode

Check a known malicious hash (EICAR test file)

check_hash("275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f")
`\

Subscribe to Threat Pulses

OTX organizes threat data into "Pulses" — curated collections of IOCs:

\`python
def get_latest_pulses(limit=5):
"""Get the latest threat intelligence pulses."""

r = requests.get(
    f"{BASE}/pulses/subscribed",
    headers=headers,
    params={"limit": limit, "page": 1},
    timeout=15
)

data = r.json()

for pulse in data.get("results", []):
    name = pulse["name"]
    created = pulse["created"]
    indicators = len(pulse.get("indicators", []))
    tags = ", ".join(pulse.get("tags", [])[:4])

    print(f"\n📡 {name}")
    print(f"   Created: {created}")
    print(f"   Indicators: {indicators}")
    print(f"   Tags: {tags}")
Enter fullscreen mode Exit fullscreen mode

get_latest_pulses()
`\

Build a Threat Feed Aggregator

\`python
def aggregate_iocs(pulse_ids):
"""Aggregate IOCs from multiple pulses into a single feed."""

all_iocs = {"IPv4": [], "domain": [], "FileHash-SHA256": [], "URL": []}

for pid in pulse_ids:
r = requests.get(f"{BASE}/pulses/{pid}/indicators", headers=headers, timeout=15)
for indicator in r.json().get("results", []):
ioc_type = indicator["type"]
if ioc_type in all_iocs:
all_iocs[ioc_type].append(indicator["indicator"])

for ioc_type, values in all_iocs.items():
if values:
unique = list(set(values))
print(f"\n{ioc_type}: {len(unique)} unique indicators")
for v in unique[:3]:
print(f" {v}")

Enter fullscreen mode Exit fullscreen mode




Aggregate IOCs from subscribed pulses

aggregate_iocs(["pulse-id-1", "pulse-id-2"])
`\

What You Can Build

  • SIEM integration — enrich alerts with OTX threat data
  • Email gateway — check sender IPs and URLs against OTX
  • Automated blocklists — generate IP/domain blocklists from pulses
  • Threat dashboard — visualize current threat landscape
  • Incident response — bulk-check IOCs from breach investigations

No Rate Limits

OTX has no published rate limits for the API. They ask for reasonable use, but there's no hard cap — making it ideal for integration into production security tools.


More free security APIs and tools on my GitHub.

Top comments (0)