API Reference
The MFA Intelligence API provides programmatic access to our made-for-advertising domain intelligence. Integrate MFA detection into your ad-tech stack, brand safety tools, or custom workflows.
https://mfa.redvolcano.uk/api/v1Authentication
All API requests require an API key. Create and manage keys from the API Keys page in your dashboard.
Never share your API key publicly. If compromised, revoke it immediately from the API Keys page and create a new one.
- Precedence: if both are present, the
Authorizationheader wins — the?api_key=query param is ignored even if the header is malformed. - Case: the
Bearerscheme is matched case-insensitively (bearer,BEARER, etc. all work). - Caching: all responses carry
Cache-Control: private, no-store. Safe to use with?api_key=since intermediaries will not retain the body. - Duplicate params: repeating a query key (e.g.
?tier=red&tier=amber) returns 400 — we do not pick one silently. - Methods: only the methods documented for each endpoint are accepted. Other verbs return 405 with an
Allowheader.
GET /api/v1/feed HTTP/1.1 Host: mfa.redvolcano.uk Authorization: Bearer mfa_your_api_key_here
GET /api/v1/feed?api_key=mfa_your_api_key_here
Rate Limits
Rate limit headers are returned on every response from a valid API key (including 404 and 429). 401 responses omit them because there is no authenticated key to identify a bucket.
X-RateLimit-LimitMax requests per hourX-RateLimit-RemainingRemaining in current windowX-RateLimit-ResetUnix timestamp of window resetHTTP/1.1 200 OK Content-Type: application/json X-RateLimit-Limit: 100000 X-RateLimit-Remaining: 99847 X-RateLimit-Reset: 1712700000
Endpoints
/api/v1/feedReturns a paginated list of MFA-flagged domains with scores, tiers, and detection signals. Invalid query values return 400 rather than being silently clamped or ignored — the response body lists each field that failed validation.
Parameters
pageintegerPage number, min 1 (default: 1)
limitintegerResults per page, 1–100 (default: 50). Values outside this range return 400.
tierstringFilter by tier: red, amber, yellow
searchstringSubstring match on domain, max 100 chars
sortstringSort by: score, domain, created_at (default: score)
orderstringSort order: asc, desc (default: desc)
curl "https://mfa.redvolcano.uk/api/v1/feed?tier=red&limit=10" \ -H "Authorization: Bearer mfa_your_key_here"
{
"domains": [
{
"id": 1,
"domain": "example-mfa.com",
"score": 87,
"tier": "red",
"created_at": "2026-03-15T10:30:00Z",
"breakdown": [
{ "key": "ads_txt", "label": "Monetization",
"score": 22, "max": 25 }
],
"signals": [
{ "key": "excessive_ads", "label": "Excessive Ads" }
]
}
],
"total": 1523,
"page": 1,
"totalPages": 31,
"isLimited": false,
"totalAvailable": 1523
}/api/v1/statsReturns aggregate statistics about the MFA domain feed — total count and breakdown by tier.
curl "https://mfa.redvolcano.uk/api/v1/stats" \ -H "Authorization: Bearer mfa_your_key_here"
{
"total": 10103,
"red": 69,
"amber": 1913,
"yellow": 8121
}/api/v1/domain/:domainLook up a specific domain. Returns the full detection record if found, or 404 if the domain is not in the feed.
Parameters
domainstringrequiredThe domain to look up (path parameter)
curl "https://mfa.redvolcano.uk/api/v1/domain/example-mfa.com" \ -H "Authorization: Bearer mfa_your_key_here"
{
"domain": "example-mfa.com",
"score": 87,
"tier": "red",
"created_at": "2026-03-15T10:30:00Z",
"breakdown": [
{ "key": "ads_txt", "label": "Monetization",
"score": 22, "max": 25 },
{ "key": "content", "label": "Content",
"score": 18, "max": 20 }
],
"signals": [
{ "key": "excessive_ads", "label": "Excessive Ads" },
{ "key": "thin_content", "label": "Thin Content" }
]
}/api/v1/domain-checksSubmit one domain, or a bulk list of up to 1,000, for an MFA assessment and ongoing monitoring. Fresh results (under 24 hours) return immediately; otherwise poll the supplied result URL. New crawls are limited to 1,000 per organisation per UTC day. Cached results and requests that join an active scan do not use crawl quota. Requested scans assess MFA signals only—clone analysis is not run.
Parameters
domainstringA single hostname or HTTP/HTTPS URL.
domainsstring[]Bulk alternative to domain; 1–1,000 values.
curl -X POST "https://mfa.redvolcano.uk/api/v1/domain-checks" \
-H "Authorization: Bearer mfa_your_key_here" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}'HTTP/1.1 202 Accepted
X-Scan-Limit: 1000
X-Scan-Remaining: 999
{
"id": "2fac35c7-6b35-4429-b42c-a2bd0f06f149",
"status": "queued",
"total": 1,
"completed": 0,
"items": [{ "domain": "example.com", "status": "queued" }],
"resultUrl": "/api/v1/domain-checks/2fac35c7-6b35-4429-b42c-a2bd0f06f149"
}/api/v1/domain-checks/:idPoll an asynchronous request. A completed assessment includes the usual score, tier, breakdown, signals and verdict. If no usable ads.txt is available, the result is inconclusive and does not overwrite the last valid assessment.
Parameters
iduuidrequiredRequest ID returned by submission.
pageintegerItem page for bulk requests (default: 1).
limitintegerItems per page, 1–100 (default: 100).
curl "https://mfa.redvolcano.uk/api/v1/domain-checks/2fac35c7-6b35-4429-b42c-a2bd0f06f149" \ -H "Authorization: Bearer mfa_your_key_here"
{
"id": "2fac35c7-6b35-4429-b42c-a2bd0f06f149",
"status": "completed",
"total": 1,
"completed": 1,
"items": [{
"domain": "example.com",
"status": "completed",
"nextScanAt": "2026-08-23T14:00:00Z",
"result": {
"verdict": "mfa_risk_detected",
"score": 54,
"tier": "amber",
"breakdown": [],
"signals": []
}
}]
}/api/v1/monitored-domains/:domainStop the day 5/15/30/60/90 and every-30-days monitoring schedule for your organisation. Monitoring continues if another organisation still tracks the same domain. Use GET on the same path to inspect its schedule and current assessment.
Parameters
domainstringrequiredThe monitored domain (path parameter).
curl -X DELETE "https://mfa.redvolcano.uk/api/v1/monitored-domains/example.com" \ -H "Authorization: Bearer mfa_your_key_here"
{ "success": true }/api/v1/ringsReturns MFA ring data — clusters of domains sharing identical ads.txt configurations, indicating coordinated MFA networks. Only hashes with 5 or more domains are returned, sorted by size descending.
curl "https://mfa.redvolcano.uk/api/v1/rings" \ -H "Authorization: Bearer mfa_your_key_here"
{
"rings": [
{
"hash": "a1b2c3d4e5f6",
"size": 12,
"domains": [
{
"domain": "site-a.com",
"tier": "red",
"score": 87,
"created_at": "2026-03-27T20:39:01Z"
}
],
"tiers": { "red": 4, "amber": 6, "yellow": 2 }
}
],
"totalRings": 82,
"totalDomainsInRings": 1532
}/api/v1/feed/exportExport up to 50,000 matching domains as JSON (default) or CSV. Subject to a separate daily export quota.
Parameters
formatstringExport format: json or csv (default: json)
tierstringFilter by tier: red, amber, yellow
# Default — JSON array of domain records curl "https://mfa.redvolcano.uk/api/v1/feed/export?tier=red" \ -H "Authorization: Bearer mfa_your_key_here" # CSV download curl "https://mfa.redvolcano.uk/api/v1/feed/export?format=csv" \ -H "Authorization: Bearer mfa_your_key_here" \ -o mfa-intelligence.csv
[
{
"id": 1,
"domain": "example-mfa.com",
"score": 87,
"tier": "red",
"created_at": "2026-03-15T10:30:00Z",
"breakdown": [
{ "key": "ads_txt", "label": "Monetization",
"score": 22, "max": 25 }
],
"signals": [
{ "key": "excessive_ads", "label": "Excessive Ads" }
]
}
]CSV format (when ?format=csv)
Signals are joined with ; and wrapped in double quotes. The response carries Content-Type: text/csv and a filename disposition header so browsers download it.
domain,score,tier,detected_at,signals example-mfa.com,87,red,2026-03-15T10:30:00Z,"Excessive Ads;Thin Content" another-site.com,72,amber,2026-03-16T08:14:22Z,"Low Content Ratio"
Code Examples
import requests
API_KEY = "mfa_your_key_here"
BASE = "https://mfa.redvolcano.uk/api/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}
# Get red-tier domains
resp = requests.get(f"{BASE}/feed", headers=headers,
params={"tier": "red", "limit": 100})
data = resp.json()
for d in data["domains"]:
print(f"{d['domain']} — Score: {d['score']} ({d['tier']})")
# Check a specific domain
resp = requests.get(f"{BASE}/domain/example.com", headers=headers)
if resp.status_code == 200:
print("Found:", resp.json())
elif resp.status_code == 404:
print("Not in MFA Intelligence")const API_KEY = "mfa_your_key_here";
const BASE = "https://mfa.redvolcano.uk/api/v1";
const headers = { Authorization: `Bearer ${API_KEY}` };
// Get feed with filters
const res = await fetch(`${BASE}/feed?tier=red&limit=50`, { headers });
const data = await res.json();
console.log(`Found ${data.total} domains`);
// Export full feed as JSON
const exportRes = await fetch(`${BASE}/feed/export`, { headers });
const allDomains = await exportRes.json();Error Codes
| Code | Meaning | Description |
|---|---|---|
| 400 | Bad Request | A query parameter failed validation. Body includes a details array with the failing field(s). |
| 401 | Unauthorized | Missing or invalid API key |
| 403 | Forbidden | API access not available for your account |
| 404 | Not Found | The requested domain was not found in the feed |
| 405 | Method Not Allowed | The method is unsupported for that endpoint. The response includes an Allow header. |
| 429 | Too Many Requests | Rate limit exceeded — check X-RateLimit-Reset header |
| 500 | Server Error | Internal error. Please try again later |
All errors return a JSON body with an error field.