API Documentation

Welcome to the CandycornDB API. Query real-time IP risk scores, screen IPs in bulk, submit community abuse reports, and pull ASN threat intelligence — all from a single credit-based surface. Every response exposes a transparent scoreAdjustments object so you can see exactly which signals drove an IP's score.

Base URL

https://candycorndb.com/api
5 MIN

Quickstart

Three steps to your first score. Grab a key from the Dashboard, pick your language, and paste. Everything else — the ASN classifier, the proxy heuristic, the community-abuse signal — is already running. Your integration just reads the JSON.

1. Get a key
Sign up, open the dashboard, and click Generate API Key. The developer tier is free (100 calls/day).
2. Send a request
One HTTP GET with the x-api-key header. Copy from any tab below.
3. Read score
0100. ≥ 70 is typical "block" territory. See the Data Dictionary for every field.
BASH
curl -X GET "https://candycorndb.com/api/public/ip-score?ip=185.220.101.44" \
  -H "x-api-key: $CANDYCORN_API_KEY"
NODE.JS
const axios = require('axios');

const { data } = await axios.get(
  'https://candycorndb.com/api/public/ip-score',
  {
    params:  { ip: '185.220.101.44' },
    headers: { 'x-api-key': process.env.CANDYCORN_API_KEY }
  }
);

if (data.score >= 70 || data.isProxy) {
  // block, CAPTCHA, or escalate to manual review
  console.warn('High-risk IP', data.ip, data.scoreReasons);
}
PYTHON
import os, requests

r = requests.get(
    "https://candycorndb.com/api/public/ip-score",
    params={"ip": "185.220.101.44"},
    headers={"x-api-key": os.environ["CANDYCORN_API_KEY"]},
    timeout=5,
)
r.raise_for_status()
data = r.json()

if data["score"] >= 70 or data.get("isProxy"):
    # block, CAPTCHA, or escalate to manual review
    print("High-risk IP", data["ip"], data.get("scoreReasons", []))

Authentication

Authenticate every request by sending your API key in the x-api-key header (case-insensitive). Missing or invalid keys return 401 Unauthorized. You can generate, rotate, and revoke keys in the Dashboard — revocations propagate within the 10-minute Redis auth cache TTL.

All endpoints are credit-based. The developer tier is metered against a rolling 24-hour window (UTC day boundary). Paid tiers (production, scale, enterprise) are metered against a rolling calendar month (UTC, resets on the 1st). Every successful call atomically charges credits in Redis before the handler executes. Single-IP calls cost 1 credit, bulk calls cost N credits (one per valid IP), and abuse-report submissions cost 1 credit. Exceeding your budget returns 429 with limit, used, window ("day" or "month"), resets, and tier fields so you can gracefully back off.

BASH
curl -X GET "https://candycorndb.com/api/public/ip-score?ip=1.2.3.4" \
  -H "x-api-key: YOUR_API_KEY"

Credit Limits by Tier

Tier Credit Pool Reset Window Bulk Cap / Call Premium Endpoints
developer 100 Daily (UTC)
production 100,000 Monthly (UTC) 100 Submit Abuse Report
scale 1,000,000 Monthly (UTC) 1,000 Abuse History, High-Risk ASNs, ASN Clusters
enterprise Unlimited Monthly (UTC) 10,000 All premium endpoints

Data Transparency

Data Sources

Every score we return is produced from five independent intelligence layers, merged, cross-validated, and re-scored continuously. No single source dominates the decision — that's how we stay ahead of IPs that slip past free blacklists and generic geolocation feeds. Every signal we use is surfaced back to you through scoreReasons / scoreAdjustments, so there are no "black box" components to audit around.

Proprietary Global Network CORE
1.5 million+ unique IPs tracked across our private honeypot network and edge collectors. Every IP that lands in our corpus is re-processed on a rolling 4-hour cadence, meaning the score you read today reflects traffic patterns from the last few hours — not a monthly dump baked a week ago. This is the layer no free list can replicate: the moment an IP first touches one of our sensors, it gets a firstSeen timestamp, and every subsequent re-observation ticks lastSeen, giving you an unbroken activity ledger per IP.
Subnet Intelligence P1 CORE
Real-time /24 neighbor analysis to catch coordinated botnet clusters before individual IPs accumulate enough reports to trip a list. When a new IP shows up on a /24 where 31 of 256 neighbors are already flagged, we surface that as networkCluster: +25 — you block the attacker on the first request, not the fifty-first. Powered by an indexed integer range query against the ipLong field, so the cost is O(log N) no matter how many IPs we track. /22 aggregation is on the P1 roadmap.
ASN & BGP Metadata P3 CORE
Deep classification of the network an IP sits on — hosting residential mobile — so you can apply the right policy to the right traffic class. A login from a residential Comcast IP and a login from an OVH VPS should never be treated the same, and with asnType you don't have to guess. Backed by our own ASN database (200k+ ASNs indexed with risk scores, prefixes, and BGP relationships) plus a hostname-override classifier that catches proxy/VPN tells the ASN alone would miss.
OSINT Aggregation EXTERNAL
Cross-referenced with 20+ public threat feeds — FireHOL Level 1, AbuseIPDB, the Tor Project exit-node list, Blocklist.de, Emerging Threats, and more — ingested continuously and de-duplicated against our own observations. Feeds vote; they don't dictate. A hit on three independent feeds raises the score more than a hit on one. Feed de-listings (an IP that was on FireHOL last week but dropped this week) are tracked too — we down-weight recovered IPs so stale blocklist data doesn't punish genuine rehabilitated traffic.
Community Reporting L5 EXTERNAL
Sybil-resistant abuse reports from our subscribers. Every reporter account passes the same gate: email verified, account older than 48 hours, and 24-hour per-IP dedup at the key level. Reports carry a reputation weight derived from the reporter's tier and historical accuracy, so a pattern-matching scraper farm can't game the corpus. Community signal lands on scored IPs as communityAbuse in scoreAdjustments — you see exactly how many reports drove the adjustment and when the most recent one fired.

Why this beats a free blacklist

Free IP blacklists are single-layer: an IP is on the list or it isn't. Our five layers compose. A brand-new hosting IP with zero feed hits can still score 60 on asnHosting (+15) + proxyInferred (+20) + networkCluster (+25) alone — High band, actionable on day zero instead of waiting weeks for a blocklist to notice. Conversely, a clean residential IP on a single noisy feed stays < 40 because the v2.3 asnResidentialBonus (−10) offsets most of the feed contribution — so you stop false-positiving your paying customers.

GET

/api/public/ip-score

The primary endpoint. Returns the risk score, threat signals (Tor/VPN), and location data for a single IPv4 address. Costs 1 credit per call. Available on all tiers (developer and up). Responses are cached for 1 hour. If the IP has never been observed, a "lite" score is returned immediately and the IP is enqueued for deep scan (de-duplicated for 1 hour per IP).

Parameters

Name Type Description
ip string (query) The IPv4 address you want to score. Required.

Example Request

BASH
curl -X GET "https://candycorndb.com/api/public/ip-score?ip=185.220.101.44" \
  -H "x-api-key: $CANDYCORN_API_KEY"
NODE.JS
const axios = require('axios');

async function scoreIp(ip) {
  const { data } = await axios.get(
    'https://candycorndb.com/api/public/ip-score',
    {
      params:  { ip },
      headers: { 'x-api-key': process.env.CANDYCORN_API_KEY },
      timeout: 5000
    }
  );
  return data;
}

const result = await scoreIp('185.220.101.44');
console.log(result.score, result.asnType, result.isProxy);
PYTHON
import os, requests

def score_ip(ip: str) -> dict:
    r = requests.get(
        "https://candycorndb.com/api/public/ip-score",
        params={"ip": ip},
        headers={"x-api-key": os.environ["CANDYCORN_API_KEY"]},
        timeout=5,
    )
    r.raise_for_status()
    return r.json()

result = score_ip("185.220.101.44")
print(result["score"], result["asnType"], result["isProxy"])

Response Comparison

The same schema is returned for every cached IP. What changes is the signal composition. The two examples below show the two ends of the spectrum — a clean residential IP vs. a known Tor exit running on a flagged hosting ASN. Every field is defined in the Data Dictionary.

Clean IP · score 0 (Low)
{
  "ip":        "73.14.58.201",
  "score":     0,           // v2.3 base-zero: 0 = fully trusted
  "asn":       "AS7922 - Comcast",
  "country":   "US",
  "isVPN":     false,
  "isTor":     false,
  "asnType":   "residential",
  "isProxy":   false,
  "firstSeen": "2025-11-04T09:11:22.000Z",
  "lastSeen":  "2026-04-22T06:48:03.910Z",
  "scoreReasons": [
    { "component": "asnResidentialBonus", "delta": -10, "detail": "Residential ISP (non-proxy)" }
  ],
  "scoreAdjustments": {
    "asnResidentialBonus": -10   // -10 delta clamped to 0 (floor)
  },
  "scoreVersion": "v2.3-base-zero"
}
High-Risk IP · score 100 (Critical)
{
  "ip":        "185.220.101.44",
  "score":     100,         // 0 + 45 + 15 + 20 + 25 + 25 = 130 → clamped to 100
  "asn":       "AS9009 - M247 Ltd",
  "country":   "DE",
  "isVPN":     true,
  "isTor":     true,
  "asnType":   "hosting",
  "isProxy":   true,
  "firstSeen": "2024-07-18T02:19:41.000Z",
  "lastSeen":  "2026-04-22T14:03:09.441Z",
  "scoreReasons": [
    { "component": "tor",            "delta": 45, "detail": "Tor Exit Node" },
    { "component": "asnHosting",     "delta": 15, "detail": "Hosting/datacenter keyword: \"m247\"" },
    { "component": "proxyInferred",  "delta": 20, "detail": "Proxy/VPN signal in ASN or hostname" },
    { "component": "networkCluster", "delta": 25, "detail": "High Risk Cluster: 185.220.101.0/24 (31 neighbors)" },
    { "component": "communityAbuse", "delta": 25, "detail": "Community abuse reports: 18 reports, weight=24" }
  ],
  "scoreAdjustments": {
    "tor":            45,
    "asnHosting":     15,
    "proxyInferred":  20,
    "networkCluster": 25,
    "communityAbuse": 25
  },
  "scoreVersion": "v2.3-base-zero"
}

Response — New IP (JIT)

If the IP has never been observed, we return a provisional "lite" score immediately (based on geo-risk only, starting from the v2.3 base-zero baseline of 0) and enqueue the full classifier for a background deep-scan. Subsequent calls for the same IP return the enriched cached shape above within minutes. firstSeen and lastSeen both collapse to "now" — this request is the first observation.

JSON
{
  "ip":        "203.0.113.17",
  "score":     0,           // v2.3 base-zero: no signals yet → 0 (Low)
  "country":   "US",
  "status":    "Analyzing",
  "message":   "New IP detected. Deep scan initiated.",
  "asnType":   "unknown",
  "isProxy":   false,
  "firstSeen": "2026-04-22T14:22:09.413Z",
  "lastSeen":  "2026-04-22T14:22:09.413Z",
  "scoreReasons":     [],
  "scoreAdjustments": {}
}

Risky-geo countries (CN, RU, KP, IR) bump the lite score to 20 (Medium) via a geoRisk adjustment; everything else starts at 0.

POST

/api/public/bulk-score

Score many IPs in a single round-trip. The server performs exactly one indexed query against the cleaned-data collection (via the ipLong integer index) regardless of batch size. Cache-miss IPs are returned immediately with status: "Analyzing" and enqueued for background deep scan. Requires Production tier or higher.

Tier Limits & Billing

Tier Max IPs / Call Credits Charged
developer Not available (403)
production 100 1 per valid, deduped IP
scale 1,000 1 per valid, deduped IP
enterprise 10,000 1 per valid, deduped IP

Only valid and deduplicated IPs are charged. Malformed IPs are returned in the invalid array and never billed. Duplicate IPs inside the same request body are collapsed silently. The whole batch is rejected with 429 if it would push you over your plan's credit budget (monthly on paid tiers) — there is no partial processing.

Example Request

BASH
curl -X POST "https://candycorndb.com/api/public/bulk-score" \
  -H "x-api-key: $CANDYCORN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ips": ["1.1.1.1", "8.8.8.8", "185.220.101.44"] }'
NODE.JS
const axios = require('axios');

async function bulkScore(ips) {
  const { data } = await axios.post(
    'https://candycorndb.com/api/public/bulk-score',
    { ips },
    {
      headers: {
        'x-api-key':    process.env.CANDYCORN_API_KEY,
        'Content-Type': 'application/json'
      },
      timeout: 10000
    }
  );
  return data.results;
}

const scored = await bulkScore(['1.1.1.1', '8.8.8.8', '185.220.101.44']);
const risky  = scored.filter(r => r.score >= 70 || r.isProxy);
PYTHON
import os, requests

def bulk_score(ips: list[str]) -> list[dict]:
    r = requests.post(
        "https://candycorndb.com/api/public/bulk-score",
        json={"ips": ips},
        headers={
            "x-api-key":    os.environ["CANDYCORN_API_KEY"],
            "Content-Type": "application/json",
        },
        timeout=10,
    )
    r.raise_for_status()
    return r.json()["results"]

scored = bulk_score(["1.1.1.1", "8.8.8.8", "185.220.101.44"])
risky  = [r for r in scored if r["score"] >= 70 or r.get("isProxy")]

Response — Transparent Score

Every result carries the same enriched shape as the single-IP endpoint: classifier labels (asnType, isProxy), temporal observability (firstSeen, lastSeen), and the full per-signal scoreAdjustments breakdown. Cache-miss IPs return status: "Analyzing" and are enqueued for a background deep-scan.

JSON
{
  "submitted":      3,
  "processed":      3,
  "hits":           2,
  "queued":         1,
  "invalid":        [],
  "invalidCount":   0,
  "creditsCharged": 3,
  "tier":           "scale",
  "results": [
    {
      // CRITICAL: hosting + Tor + flagged /24 + recent abuse (clamped at 100)
      "ip":        "185.220.101.44",
      "score":     100,
      "asn":       "AS9009 - M247 Ltd",
      "country":   "DE",
      "city":      "Frankfurt",
      "isp":       "M247 Ltd",
      "isVPN":     false,
      "isTor":     true,
      "asnType":   "hosting",
      "isProxy":   true,
      "status":    "Analyzed",
      "scoreAdjustments": {
        "tor":            45,   // known Tor exit node
        "asnHosting":     15,   // hosting/datacenter ASN
        "proxyInferred":  20,   // ISP/hostname proxy signal
        "networkCluster": 25,   // /24 cluster risk > 60 (P1)
        "communityAbuse": 25    // weighted abuse reports, 90d
      },
      "firstSeen": "2024-07-18T02:19:41.000Z",
      "lastSeen":  "2026-04-22T14:03:09.441Z",
      "cleanedAt": "2026-04-22T14:03:09.441Z"
    },
    {
      // CLEAN: residential ISP, v2.3 trust bonus fires
      "ip":        "73.14.58.201",
      "score":     0,
      "asn":       "AS7922 - Comcast",
      "country":   "US",
      "isVPN":     false,
      "isTor":     false,
      "asnType":   "residential",
      "isProxy":   false,
      "status":    "Analyzed",
      "scoreAdjustments": {
        "asnResidentialBonus": -10  // clamped to 0 floor
      },
      "firstSeen": "2025-11-04T09:11:22.000Z",
      "lastSeen":  "2026-04-22T06:48:03.910Z",
      "cleanedAt": "2026-04-22T06:48:03.910Z"
    },
    {
      // NEW: cache-miss — v2.3 lite score (0 baseline), deep scan queued
      "ip":        "203.0.113.17",
      "score":     0,
      "country":   "US",
      "status":    "Analyzing",
      "asnType":   "unknown",
      "isProxy":   false,
      "firstSeen": "2026-04-22T14:22:09.413Z",
      "lastSeen":  "2026-04-22T14:22:09.413Z",
      "message":   "New IP detected. Deep scan initiated."
    }
  ]
}

The scoreAdjustments object is the "why behind the score" — each key is the contribution (in points) of one signal toward the final score. An empty object ({}) means no risk signals fired. Missing keys mean the signal was not evaluated (e.g., pre-v2 historical records). Use this to build explainable fraud rules in your own system instead of treating the score as a black box.

Data Dictionary

Every field returned by /api/public/ip-score and /api/public/bulk-score, in one place. Fields marked RISK are the most useful for gating decisions; fields marked META are metadata for UX or analytics.

score integer · 0–100 RISK
The unified trust score, produced by the v2.3 base-zero engine. 0 is fully trusted, 100 is maximum risk. The four canonical risk bands map one-to-one with production gating:

0–14 Low · allow. Clean residential / mobile / verified crawlers.
15–39 Medium · monitor or rate-limit. One mild signal firing (hosting, proxy, or subnet).
40–69 High · CAPTCHA / step-up auth / enrichment. Multiple stacking signals.
70–100 Critical · block or route to manual review.

Recommended predicates: score ≥ 40 || isProxy for aggressive fraud-sensitive flows, score ≥ 70 for pure blocking. Pre-v2.3 consumers that gated on ≥ 50 should migrate to ≥ 40 || isProxy to preserve equivalent selectivity.
asnType enum · string RISK
Coarse business-class label for the network the IP sits on. One of: hosting residential mobile unknown

"hosting" is a high-risk indicator. Real user traffic almost never originates from a cloud/VPS/colo ASN (AWS, GCP, OVH, Hetzner, DigitalOcean, …), so a "hosting" classification on a login/checkout/signup request is nearly always a bot, scraper, proxy, or a sophisticated attacker routing through rented infrastructure. The classifier adds +15 to the score for any hosting IP. "residential" and "mobile" are the expected values for genuine human traffic; "unknown" means the ISP string didn't match any keyword list (treat as neutral).
isProxy boolean RISK
Inferred proxy / VPN / anonymization signal. Set to true when either (a) the ISP/ASN name matches a hosting-infrastructure keyword, or (b) the reverse-DNS hostname contains an explicit tell (vps, server, node, proxy, vpn). Deliberately broader than asnType === "hosting" — a consumer ISP with a "*-vpn.example.net" PTR will flag isProxy: true but asnType: "residential". Adds +20 to the score. Prefer this over the legacy isVPN field in new integrations.
firstSeen ISO 8601 timestamp · nullable META
The first time CandycornDB observed this specific IP across any data source (feed ingestion, abuse report, API query, or JIT deep-scan). Written exactly once per IP — never updated. Use this to filter "long-lived known threats" vs. "just-emerged infrastructure" (fresh firstSeen + high score often indicates a brand-new botnet node still spinning up). May be null for historical rows that pre-date the v2.2 schema cut.
lastSeen ISO 8601 timestamp META
The most recent time we re-processed this IP (every cleaner cycle refreshes it). Pair with firstSeen to reason about IP lifespan. A stale lastSeen (e.g., months old) for a still-flagged IP means the threat signal came from long-term feeds rather than recent activity — useful for tuning false-positive tolerance.
scoreReasons object[] · { component, delta, detail } RISK
The "transparency array" — structured explanations for every signal that contributed to the score, in the order they were applied. Each entry is an object: component (the reason code, e.g. "tor"), delta (signed integer contribution, e.g. +45 or -10), and detail (human-readable context). Render detail verbatim in fraud-review UIs, or iterate on component/delta to build custom rule logic. Empty array means no risk signals fired — the IP is clean.
scoreAdjustments object · string → integer RISK
Machine-readable counterpart to scoreReasons. Each key is a reason code, each value is the signed point contribution. Common keys: tor (+45), fireholListed (+35), riskStackFireholUnknownIsp (+30), asnHighRisk (+25), networkCluster (+25), blocklistDeListed (+25), proxyInferred (+20), hostnameSuspicious (+20), asnHosting (+15), communityAbuse (+5…+40), asnMobileBonus (−5), asnResidentialBonus (−10), hostnameLegitimate (−15), asnTrusted (−30), trustedCrawler (−50). The object is sparse — only keys that fired are present. An empty object means no signals fired.
isVPN / isTor boolean RISK
Legacy threat flags. isTor is a hard boolean (the IP appears on the Tor Project's exit-node list); isVPN is a narrow heuristic that fires on "vpn" in the ISP string. For new integrations prefer isProxy (broader) and asnType === "hosting". Kept in the response for backwards compatibility.
asn / country / city / isp string META
Network and geo context. asn is the "AS12345 - Org Name" form; country is an ISO-3166-1 alpha-2 code. city and isp are present on the /bulk-score response; the single-IP endpoint omits them to keep cached payloads tight.
status enum · string META
"Analyzed" — full scoring complete, every field populated from the classifier output. "Analyzing" — first-ever observation; you got a provisional lite score (geo-risk only) and a background deep-scan was enqueued. The same IP on the next call will return "Analyzed".
scoreVersion string META
The scoring algorithm version that produced this record. Current: v2.3-base-zero. Pin your integration tests against this value so a silent scoring-model change surfaces in your CI instead of production.

Subnet Intelligence

Subnet-clustering signals are folded directly into the scoreAdjustments.networkCluster component of every bulk-score response — no separate endpoint is required. During the cleaner pass, each IP's /24 neighborhood is scanned via an indexed integer range query (ipLong >= low AND ipLong < high). Neighbor count is bucketed into a clusterRisk tier (0 / 50 / 70 / 85); anything above 60 contributes a flat +25 to the score. /22 aggregation is on the P1 roadmap. The example below shows how this appears in a bulk response for a flagged neighborhood.

JSON (excerpt from /api/public/bulk-score)
{
  "ip": "185.220.101.44",
  "score": 95,
  "scoreAdjustments": {
    "tor":            45,
    "asnHighRisk":    25,
    "networkCluster": 25    // /24 clusterRisk > 60 (31 of 256 neighbors flagged)
  }
}
POST

/api/public/report

Submit a community abuse report for an IP. Reports feed the shared threat corpus and influence the scoreAdjustments.communityAbuse signal (a graduated +5 / +15 / +25 / +40 contribution based on reporter-weighted totalWeight over the last 90 days) for all subscribers. Costs 1 credit per submission. Requires Production tier or higher (the developer tier cannot contribute).

24-hour deduplication: the same API key cannot file more than one report against the same IP in a rolling 24-hour window. Duplicate submissions return 409 Conflict with a dedupTtlSeconds field indicating the remaining cool-down. Dedup is enforced atomically in Redis (SET NX EX) so concurrent submissions are safe.

Body Parameters

Name Type Description
ip string (required) The offending IPv4 address.
category integer or int[] (required) One or more category codes in [1, 23]. See table below.
comment string (optional) Free-text context, max 1024 characters.
attackedHost string (optional) Hostname or domain that was targeted.

Valid Category Codes (1–23)

Code Category Code Category
1DNS Compromise13Spoofing
2DNS Poisoning14Brute-Force Attack
3Fraud Orders15Bad Web Bot
4DDoS Attack16Exploited Host
5FTP Brute-Force17Web App Attack
6Ping of Death18SSH
7Phishing19IoT Targeted
8Fraud VoIP20Credential Stuffing
9Open Proxy21Scraping / Abuse
10Web Spam22Carding / Payment Fraud
11Email Spam23Account Takeover
12Blog Spam

Request

BASH
curl -X POST "https://candycorndb.com/api/public/report" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ip": "203.0.113.17",
    "category": [18, 14],
    "comment": "SSH brute-force against prod bastion",
    "attackedHost": "bastion.example.com"
  }'

Response (201 Created)

JSON
{
  "success": true,
  "reportId": "663f2a1c8e2d4b0012a9f7b1",
  "ip": "203.0.113.17",
  "category": [18, 14],
  "reportedAt": "2026-04-22T14:22:09.413Z",
  "creditsCharged": 1
}
GET

/api/public/abuse/:ip

Retrieve an aggregated community abuse summary for an IP. Returns up to 100 of the most recent reports along with category counts and the most-recent timestamp. Costs 1 credit per call. Requires Scale tier or higher. Reporter identities are stripped from the response.

Request

BASH
curl -X GET "https://candycorndb.com/api/public/abuse/203.0.113.17" \
  -H "x-api-key: YOUR_API_KEY"

Response

JSON
{
  "ip": "203.0.113.17",
  "totalReports": 27,
  "truncated": false,
  "mostRecent": "2026-04-22T14:22:09.413Z",
  "categories": {
    "14": 12,
    "18": 11,
    "17": 4
  },
  "reports": [
    {
      "ipLong":       3405803801,
      "ipAddress":    "203.0.113.17",
      "reporterTier": "scale",
      "category":     [18, 14],
      "comment":      "SSH brute-force against prod bastion",
      "attackedHost": "bastion.example.com",
      "reportedAt":   "2026-04-22T14:22:09.413Z"
    }
  ]
}

ASN Intelligence

Query Autonomous System metadata — names, countries, risk scores, and relationships — under the /api/asn/* prefix. All ASN endpoints share the same credit-based surface (1 credit per call) and respect your plan's reset window (daily for developer, monthly for paid tiers). Basic lookups (:asnNumber, /ip/:ip, /related, /search, /stats) are available to every paying tier.

Available Endpoints

Method Path Description Tier
GET /api/asn/asn/:asnNumber Lookup one ASN by number (e.g. AS9009). Production+
GET /api/asn/ip/:ipAddress Resolve an IP to its owning ASN. Production+
GET /api/asn/asn/:asnNumber/related Peer / upstream / downstream ASNs. Production+
GET /api/asn/search Search by name / country / risk range. Production+
GET /api/asn/stats Global ASN database statistics. Production+
GET /api/asn/high-risk Rank ASNs by risk score. Scale / Enterprise only
GET /api/asn/clusters Coordinated ASN clusters (fraud rings). Scale / Enterprise only

Example — ASN Lookup

BASH
curl -X GET "https://candycorndb.com/api/asn/asn/AS9009" \
  -H "x-api-key: YOUR_API_KEY"
GET

/api/asn/high-risk & /api/asn/clusters

Premium intelligence surfaces available on Scale and Enterprise tiers. Requests from lower tiers are rejected with 403 Forbidden and a requiredTier hint. Costs 1 credit per call.

Query Parameters — /api/asn/high-risk

Name Type Description
minRiskScore integer (default 8) Minimum risk score to include (1–10 scale).
limit integer (default 50) Maximum ASNs to return.
relationships boolean (default false) Include peer/upstream relationships inline.

Query Parameters — /api/asn/clusters

Name Type Description
minSize integer (default 3) Minimum ASNs per cluster.
minRisk integer (default 0) Minimum average risk score in the cluster.
limit integer (default 10) Maximum clusters returned.

Request — High-Risk ASNs

BASH
curl -X GET "https://candycorndb.com/api/asn/high-risk?minRiskScore=8&limit=25" \
  -H "x-api-key: YOUR_API_KEY"

Request — ASN Clusters

BASH
curl -X GET "https://candycorndb.com/api/asn/clusters?minSize=3&minRisk=7&limit=10" \
  -H "x-api-key: YOUR_API_KEY"
GET

/api/asn/stats

Returns global ASN database statistics — total ASNs indexed, risk-score distribution, top countries, and cluster summaries. Useful for building dashboards or monitoring database growth. Costs 1 credit per call. Available on all paying tiers.

BASH
curl -X GET "https://candycorndb.com/api/asn/stats" \
  -H "x-api-key: YOUR_API_KEY"

Errors & Rate Limits

We use standard HTTP status codes. Every error response is a JSON object with at minimum an error field; rate-limit and tier-gate responses include additional diagnostic fields so you can react programmatically.

200 Success. Data returned.
201 Created. Used by POST /api/public/report on a new abuse report.
400 Bad Request. Missing, malformed, or out-of-range parameter (e.g. invalid IP, category outside 1–23, bulk body without ips).
401 Unauthorized. Missing or invalid x-api-key header.
403 Forbidden. Your tier does not include this endpoint. The response contains currentTier and requiredTier (or upgradeTo) fields.
409 Conflict. You already reported this IP in the last 24 hours. Response includes dedupTtlSeconds.
429 Rate Limit Exceeded. Response includes limit, used, cost, tier, window ("day" or "month"), and resets so you can back off or upgrade.
500 Internal error. Retry with exponential backoff; if the issue persists, contact support.