← Back to Blog
February 1, 2025 • 18 min read • API Documentation

AdverseMonitor API Documentation: Complete Developer Guide

Everything you need to integrate dark web threat intelligence into your applications, SIEMs, and security workflows
4
API Endpoints
v1
Current API Namespace
JSON
Response Format
Signed
Webhook Delivery

The AdverseMonitor API provides programmatic access to the collected threat records available to your plan. Whether you're building a custom security dashboard, integrating with your SIEM, or automating incident response workflows, this API gives you the data you need to stay ahead of threats.

This documentation covers authentication, threat queries, actor search, and signed webhook delivery through the implemented REST interface.

Quick Start

Use the following path to make a first API call:

Prerequisites: Protection or Defend is required for permanent API keys. Trial accounts may generate a limited, read-only trial key; Detection has no API access.

Step 1: Generate Your API Key

  1. Log into your AdverseMonitor dashboard
  2. Navigate to Settings → API Access
  3. Click "Create New API Key"
  4. Enter a descriptive name (e.g., "Production SIEM Integration")
  5. Copy and securely store the generated key immediately—it won't be shown again
Security Note: Your API key provides access to sensitive threat intelligence. Never commit it to version control, share it in plain text, or expose it in client-side code.

Step 2: Make Your First Request

cURL
curl -X GET "https://platform.adversemonitor.com/api/v1/threats?limit=10" \
  -H "Authorization: Bearer am_live_your_api_key_here" \
  -H "Content-Type: application/json"

If successful, you'll receive a JSON response containing the latest threat intelligence matching your alert profile configuration.

Authentication

The AdverseMonitor API uses Bearer token authentication. Every request must include your API key in the Authorization header.

API Key Format

API keys follow a specific format for easy identification:

Format
am_live_[64 hexadecimal characters]

Example: am_live_a1b2c3d4e5f6789012345678901234567890abcdef1234567890abcdef12345678

Request Header

Include the Authorization header in all API requests:

Header
Authorization: Bearer am_live_your_api_key_here

Authentication Errors

Status Code Error Description
401 Missing Authorization header Include Authorization: Bearer am_live_xxx header
401 Invalid API key Key doesn't exist, is revoked, or has invalid format
403 API access requires Protection or Defend subscription Upgrade your subscription plan to access the API

Code Examples

Python

Python
import requests

API_KEY = "am_live_your_api_key_here"
BASE_URL = "https://platform.adversemonitor.com/api/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.get(f"{BASE_URL}/threats", headers=headers)
data = response.json()
print(f"Retrieved {len(data['data'])} threats")

JavaScript / Node.js

JavaScript
const API_KEY = 'am_live_your_api_key_here';
const BASE_URL = 'https://platform.adversemonitor.com/api/v1';

async function fetchThreats() {
  const response = await fetch(`${BASE_URL}/threats`, {
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    }
  });

  const data = await response.json();
  console.log(`Retrieved ${data.data.length} threats`);
  return data;
}

fetchThreats();

Go

Go
package main

import (
    "fmt"
    "io"
    "net/http"
)

const apiKey = "am_live_your_api_key_here"
const baseURL = "https://platform.adversemonitor.com/api/v1"

func main() {
    client := &http.Client{}
    req, _ := http.NewRequest("GET", baseURL+"/threats", nil)
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}

Rate Limits

Rate limits protect API availability and ensure fair usage across all customers. Limits vary by subscription plan:

Plan Per Minute Per Day Data History
Protection 10 requests 1,000 requests 365 days
Defend Unlimited Unlimited Full history

Rate Limit Headers

Every API response includes headers to help you track your usage:

Header Description
X-RateLimit-Limit Maximum requests allowed in current window
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Unix timestamp when the rate limit resets

Handling Rate Limit Errors

When you exceed rate limits, the API returns a 429 Too Many Requests response:

Response
{
  "error": "Rate limit exceeded",
  "retry_after": 45
}

Implement exponential backoff in your integration:

Python
import time
import requests

def fetch_with_retry(url, headers, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 429:
            retry_after = response.json().get('retry_after', 60)
            print(f"Rate limited. Waiting {retry_after} seconds...")
            time.sleep(retry_after)
            continue

        return response

    raise Exception("Max retries exceeded")

API Endpoints

The AdverseMonitor API provides four core endpoints for accessing threat intelligence:

List Threats

GET /api/v1/threats

Retrieve threat intelligence data filtered by your alert profile configuration. Supports pagination, filtering, and date ranges.

Query Parameters

Parameter Type Required Description
limit integer Optional Number of results to return (1-100, default: 50)
cursor string Optional Pagination cursor from previous response
category string Optional Filter by category (must be in your alert profile scope)
country string Optional Filter by victim country (must be in your alert profile scope)
since ISO 8601 Optional Return threats published after this date

Response Fields

Response Schema
{
  "data": [
    {
      "id": "abc123-unique-post-id",
      "title": "LockBit claims attack on manufacturing company",
      "summary": "LockBit ransomware group has posted...",
      "category": "Ransomware",
      "threat_actors": ["LockBit", "LockBit 3.0"],
      "victims": {
        "countries": ["United States"],
        "industries": ["Manufacturing"],
        "organizations": ["ACME Corp"],
        "domains": ["acmecorp.com"]
      },
      "risk_level": "critical",
      "ai_analysis": "High confidence ransomware attack...",
      "published_at": "2025-02-01T14:32:00Z"
    }
  ],
  "meta": {
    "total": 156,
    "returned": 50,
    "cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNS...",
    "filters_applied": {
      "category": null,
      "country": null,
      "since": null
    }
  }
}

Example Request

cURL
# Get latest 25 ransomware threats
curl -X GET "https://platform.adversemonitor.com/api/v1/threats?limit=25&category=Ransomware" \
  -H "Authorization: Bearer am_live_your_api_key"

# Get threats from the last 24 hours
curl -X GET "https://platform.adversemonitor.com/api/v1/threats?since=2025-01-31T00:00:00Z" \
  -H "Authorization: Bearer am_live_your_api_key"

# Paginate through results
curl -X GET "https://platform.adversemonitor.com/api/v1/threats?cursor=eyJjcmVhdGVkX2F0..." \
  -H "Authorization: Bearer am_live_your_api_key"

Search Threats

GET /api/v1/threats/search

Search threat intelligence by keyword. Searches across titles, summaries, threat actors, and victim organizations.

Query Parameters

Parameter Type Required Description
q string Required Search query (minimum 3 characters)
limit integer Optional Number of results (1-50, default: 25)

Example Request

cURL
# Search for LockBit mentions
curl -X GET "https://platform.adversemonitor.com/api/v1/threats/search?q=LockBit&limit=20" \
  -H "Authorization: Bearer am_live_your_api_key"

# Search for your domain
curl -X GET "https://platform.adversemonitor.com/api/v1/threats/search?q=yourcompany.com" \
  -H "Authorization: Bearer am_live_your_api_key"

Threat Actors

GET /api/v1/threat-actors

Get aggregated threat actor analytics including mention counts, last activity dates, and associated threat categories.

Query Parameters

Parameter Type Required Description
limit integer Optional Number of actors to return (1-100, default: 50)

Response Schema

Response
{
  "data": [
    {
      "name": "LockBit",
      "mention_count": 342,
      "last_seen": "2025-02-01T18:45:00Z",
      "categories": ["Ransomware", "Data Breach"]
    },
    {
      "name": "ALPHV",
      "mention_count": 187,
      "last_seen": "2025-01-31T22:12:00Z",
      "categories": ["Ransomware"]
    }
  ],
  "meta": {
    "total": 89,
    "returned": 50
  }
}

Alert Profile Filtering

A unique feature of the AdverseMonitor API is automatic data filtering based on your alert profiles. This ensures you only receive threat intelligence relevant to your organization.

Important: You must have at least one active alert profile with configured filters to receive any data from the API. Profiles without any filters (categories, countries, etc.) will return empty results.

How Filtering Works

  1. Configure alert profiles in your dashboard with categories, countries, industries, threat actors, organizations, or domains
  2. The API combines filters from all your active profiles using OR logic
  3. Threats matching ANY of your configured filters are returned
  4. If you request a specific filter parameter (e.g., ?country=Germany), it must be within your profile scope

Filter Types

Filter Description Example Values
categories Threat categories to monitor Ransomware, Data Breach, Infostealer Logs
countries Victim countries to track United States, Germany, Japan
industries Target industries Healthcare, Finance, Manufacturing
threat_actors Specific threat groups LockBit, ALPHV, Cl0p
organizations Named organizations Your company name, partners
domains Domain names to watch yourcompany.com, partner.com

Example Scenario

If your alert profile has:

  • Categories: Ransomware, Data Breach
  • Countries: United States, Canada

The API returns threats that match:

  • Ransomware attacks affecting any country, OR
  • Data breaches affecting any country, OR
  • Any threat type affecting United States, OR
  • Any threat type affecting Canada

Webhooks

Webhooks deliver matching records to your configured endpoint. Collection and delivery latency varies, so consumers should retain retry and reconciliation logic.

Webhook Setup

  1. Navigate to Settings → API Access → Webhooks
  2. Click "Add Webhook"
  3. Enter your HTTPS endpoint URL
  4. Copy and save the generated webhook secret
  5. Optionally select event types to filter

Webhook Payload

Webhook Payload
{
  "event": "threat.new",
  "timestamp": "2025-02-01T14:32:00Z",
  "data": {
    "id": "abc123-unique-post-id",
    "title": "LockBit claims attack on manufacturing company",
    "summary": "LockBit ransomware group has posted...",
    "category": "Ransomware",
    "threat_actors": ["LockBit"],
    "victims": {
      "countries": ["United States"],
      "industries": ["Manufacturing"],
      "organizations": ["ACME Corp"],
      "domains": ["acmecorp.com"]
    },
    "risk_level": "critical",
    "published_at": "2025-02-01T14:32:00Z"
  }
}

Signature Verification

Every webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 signature. Always verify this signature to ensure the request came from AdverseMonitor.

Verification in Python

Python
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret_here"

def verify_signature(payload, signature):
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Webhook-Signature')

    if not signature or not verify_signature(request.data, signature):
        abort(401)  # Reject invalid signatures

    data = request.json
    print(f"Received threat: {data['data']['title']}")

    # Process the threat...

    return '', 200

Verification in Node.js

JavaScript
const express = require('express');
const crypto = require('crypto');

const app = express();
const WEBHOOK_SECRET = 'your_webhook_secret_here';

function verifySignature(payload, signature) {
  const expected = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];

  if (!signature || !verifySignature(req.body, signature)) {
    return res.status(401).send('Invalid signature');
  }

  const data = JSON.parse(req.body);
  console.log(`Received threat: ${data.data.title}`);

  // Process the threat...

  res.status(200).send();
});

Webhook Best Practices

  • Respond quickly: Return a 2xx status within 30 seconds to acknowledge receipt
  • Process asynchronously: Queue webhook data for background processing
  • Handle retries: Implement idempotency; the same webhook may be delivered multiple times
  • Use HTTPS: Only HTTPS endpoints are supported for security
  • Monitor failures: Check webhook delivery status in your dashboard

Error Handling

The API returns standard HTTP status codes with detailed error messages in JSON format.

Error Response Format

Error Response
{
  "error": "Human-readable error message",
  "retry_after": 45  // Only present for rate limit errors
}

Status Codes

Code Meaning Resolution
200 Success Request completed successfully
400 Bad Request Check query parameters (e.g., search query too short)
401 Unauthorized Invalid or missing API key
403 Forbidden Plan doesn't include API access, or filter outside scope
429 Too Many Requests Wait for retry_after seconds
500 Internal Server Error Retry the request; contact support if persistent

SIEM Integration

The AdverseMonitor API returns JSON that can be mapped into common Security Information and Event Management (SIEM) ingestion workflows.

Splunk Integration

Python (Splunk HEC)
import requests
from datetime import datetime, timedelta

# AdverseMonitor API
AM_API = "https://platform.adversemonitor.com/api/v1/threats"
AM_KEY = "am_live_your_api_key"

# Splunk HEC
SPLUNK_HEC = "https://your-splunk:8088/services/collector/event"
HEC_TOKEN = "your-hec-token"

# Fetch threats from last hour
since = (datetime.utcnow() - timedelta(hours=1)).isoformat() + "Z"
response = requests.get(
    AM_API,
    headers={"Authorization": f"Bearer {AM_KEY}"},
    params={"since": since}
)

# Send each threat to Splunk
for threat in response.json()["data"]:
    event = {
        "event": threat,
        "sourcetype": "adversemonitor:threat",
        "index": "threat_intelligence"
    }
    requests.post(
        SPLUNK_HEC,
        headers={"Authorization": f"Splunk {HEC_TOKEN}"},
        json=event,
        verify=True
    )

print(f"Sent {len(response.json()['data'])} threats to Splunk")

Microsoft Sentinel (Logic App)

Create a Logic App with these components:

  1. Recurrence trigger: Every 15 minutes
  2. HTTP action: GET request to AdverseMonitor API
  3. Parse JSON: Extract threat data
  4. For each: Loop through threats
  5. Send data to Log Analytics: Ingest into your workspace

Elastic Security (Logstash)

Logstash Config
input {
  http_poller {
    urls => {
      adversemonitor => {
        url => "https://platform.adversemonitor.com/api/v1/threats"
        headers => {
          "Authorization" => "Bearer am_live_your_api_key"
        }
      }
    }
    schedule => { cron => "*/10 * * * *" }
    codec => "json"
  }
}

filter {
  split { field => "[data]" }
  mutate {
    rename => { "[data]" => "threat" }
  }
}

output {
  elasticsearch {
    hosts => ["https://your-elastic:9200"]
    index => "adversemonitor-threats-%{+YYYY.MM.dd}"
  }
}

Frequently Asked Questions

What programming languages are supported? +

The AdverseMonitor REST API works with any programming language that can make HTTP requests. We provide code examples for Python, JavaScript/Node.js, Go, and cURL, but you can use any language including Ruby, PHP, Java, C#, Rust, or shell scripts.

How do I change my rate limit? +

Rate limits are determined by your subscription plan. To increase limits, upgrade from Protection (10 req/min, 1,000/day) to Defend (unlimited). Contact sales for enterprise requirements.

Can I have multiple API keys? +

Yes, you can create multiple API keys for different integrations (e.g., separate keys for Splunk, custom dashboards, and automation scripts). Each key shares your account's rate limits. Revoke unused keys promptly.

Why am I getting empty results? +

Empty results typically mean: (1) No active alert profiles configured, (2) Alert profiles have no filters defined, (3) No threats match your configured filters, or (4) Requested filter parameter (category/country) is outside your profile scope. Verify your alert profiles in the dashboard.

Is there a sandbox/test environment? +

The API uses production data with your actual alert profile configuration. For development, we recommend creating a separate API key labeled "development" that you can revoke after testing. Rate limits apply to all keys equally.

How fresh is the threat data? +

AdverseMonitor exposes collected threat records through the API. Use webhooks for configured matches or polling for scheduled retrieval; collection and delivery latency varies. The published_at field indicates when the threat was first observed.

What happens if my webhook endpoint is down? +

A failed delivery is recorded, but automatic retry is not promised. Consumers should monitor their endpoint and poll the API to reconcile any delivery gap.

Can I filter webhooks by threat type? +

Yes, when creating a webhook you can select specific event types to receive. For example, receive only ransomware alerts or only critical-severity threats. This reduces noise and ensures your endpoint only processes relevant notifications.

Ready to Integrate Dark Web Intelligence?

Start with the limited read-only trial API, then evaluate Protection only when the production API fits a verified workflow.

Scan Your Domain Free

No credit card required • 14-day trial • Limited read-only API

Getting Help

We're here to help you succeed with your integration:

When reporting issues, include:

  • Your API key prefix (first 16 characters: am_live_xxxxxxxx)
  • Request timestamp and endpoint
  • Full error response received
  • Code snippet if relevant

Related Articles