API reference
Every endpoint is available under two prefixes. /api/v1 keeps the original response shape so existing integrations keep working unchanged. /api/v2 returns the same data inside a consistent envelope. Timestamps are always UTC ISO-8601; *_display fields carry the human rendering in Asia/Kuala_Lumpur (GMT+8). Read endpoints are public; ingest and heartbeat require a collector key.
Response envelope
v2 success
{
"success": true,
"data": { ... },
"meta": { "generated_at": "...", "api_version": 2 }
}v2 error
{
"success": false,
"error": {
"code": "INVALID_IP",
"message": "Provide a valid IPv4 or IPv6 address."
}
}v1 responses keep ok and the legacy error slug, and additionally carry success, error_code and a human message. No v1 field has been removed.
Status codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Ingest created a new indicator |
400 | Invalid input; the message names the offending field |
401 | Missing, unknown or disabled API key |
404 | No such endpoint |
405 | Wrong method; the Allow header lists the valid ones |
413 | Request body exceeds the 8 KB limit |
415 | Content-Type must be application/json |
204 | Heartbeat accepted; no body returned |
429 | Rate limited; honour the Retry-After header |
503 | A dependency is unavailable; retry shortly |
/api/v1/check?ip={address}Check a single address
Listed status, risk score, blocklist window, counts, geolocation and ASN. An unlisted address returns HTTP 200 with listed=false, never 404.
Request
curl -s 'https://abuse.secureinsight.my/api/v1/check?ip=203.0.113.10'
Response
{
"ok": true,
"success": true,
"listed": true,
"ip": "203.0.113.10",
"severity": "High",
"severity_score": 62,
"detections": 14,
"sources": 2,
"first_seen": "2026-08-01T04:11:02+00:00",
"first_seen_display": "2026-08-01 12:11 GMT+8",
"last_seen": "2026-08-22T06:15:09+00:00",
"feed": "10/15/30d lists",
"geo": {
"country": "Brazil",
"country_code": "BR",
"city": "Belo Horizonte",
"asn": 18881,
"asn_label": "AS18881",
"org": "TELEFONICA BRASIL S.A",
"rdns": "",
"pending": false
}
}/api/v1/ip/{ip}Full address report
Everything /check returns, plus the reporting sensors and the complete observation history for that address.
Request
curl -s 'https://abuse.secureinsight.my/api/v2/ip/203.0.113.10'
Response
{
"success": true,
"data": {
"ip": "203.0.113.10",
"listed": true,
"severity": "High",
"severity_breakdown": {
"volume": 45, "corroboration": 10,
"signal": 12, "recency": 20
},
"sensors": [
{ "name": "SSH Sensor 01", "observations": 14 }
],
"events": [ ... ]
},
"meta": { "generated_at": "...", "api_version": 2 }
}/api/v1/feedBulk feed
Paged, filterable, sortable indicator list. Parameters: days (1-30), limit (1-500), page or offset, status (active|expired|all), reason, severity, country, asn, q, sort (last_seen|first_seen|detections|sources|ip|severity), order (asc|desc).
Request
curl -s 'https://abuse.secureinsight.my/api/v1/feed?days=10&severity=high&sort=detections&limit=50'
Response
{
"ok": true,
"success": true,
"window_days": 10,
"count": 50,
"total": 214,
"events": [ ... ],
"filters": { "status": "active", "severity": "high" },
"pagination": {
"page": 1, "pages": 5,
"limit": 50, "offset": 0,
"has_more": true
}
}/api/v2/statsPlatform statistics
The numbers behind the dashboard: totals, 24-hour activity, category mix, top countries and networks, collector health and the 14-day activity series.
Request
curl -s 'https://abuse.secureinsight.my/api/v2/stats'
Response
{
"success": true,
"data": {
"totals": { "records": 4653, "unique_ips": 4610 },
"recent": { "detections_24h": 118, "new_ips_24h": 31 },
"categories": [ { "key": "ssh", "detections": 1425 } ],
"countries": [ ... ],
"networks": [ ... ],
"activity": [ { "date": "2026-08-22", "records": 42 } ],
"collector_summary": { "total": 8, "live": 4 }
}
}/api/v2/sensorsCollector health
Public-safe sensor roster and reporting state, with the cadence each state is judged against. No key material, labels or source addresses are exposed.
Request
curl -s 'https://abuse.secureinsight.my/api/v2/sensors'
Response
{
"success": true,
"data": {
"sensors": [
{
"name": "SSH Sensor 01",
"type": "SSH Sensor",
"state": "reporting",
"silence_hours": 1.0,
"observations": 1425,
"cadence": {
"typical_gap_hours": 6.4,
"p90_gap_hours": 23.2,
"reporting_within_hours": 23.2,
"overdue_after_hours": 34.8,
"derived_from_history": true
}
}
],
"summary": {
"total": 8, "active": 7, "reporting": 7,
"idle": 0, "overdue": 0, "retired": 1
},
"note": "State reflects observation recency ..."
}
}/api/v2/sensors/heartbeatCollector heartbeat
Liveness check-in. Creates no event, moves no detection counter and does not touch last_used_at - it updates last_seen_at only. Call it once per collector cycle (every 5 minutes); a sensor is Overdue after 4 missed cycles. Heartbeat state is per sensor identity, so a host running several sensors must check in once per key.
Request
curl -s -X POST \ -H "Authorization: Bearer $ABUSE_RADAR_KEY" \ https://abuse.secureinsight.my/api/v2/sensors/heartbeat
Response
HTTP/1.1 204 No Content (no body) Health is then reported by GET /api/v2/sensors: health healthy | overdue | unmonitored | pending | retired last_heartbeat_at 2026-08-22T11:47:56+00:00 last_observation_at 2026-08-21T09:45:04+00:00
/api/v1/eventsSubmit an observation
Collector ingest. Upserts on (ip, reason_code): re-submitting the same pair adds to its detection count instead of creating a duplicate. Returns 201 when the indicator is new and 200 when an existing one is updated.
Request
curl -s -X POST \
-H "Authorization: Bearer $ABUSE_RADAR_KEY" \
-H "Content-Type: application/json" \
-d '{
"ip": "203.0.113.10",
"reason_code": "ssh_auth_abuse",
"detected_at": "2026-08-22T06:15:09+00:00",
"count": 3
}' \
https://abuse.secureinsight.my/api/v1/eventsResponse
{
"ok": true,
"success": true,
"action": "updated",
"ip": "203.0.113.10",
"reason_code": "ssh_auth_abuse",
"detection_count": 17,
"sources": 2,
"detected_at": "2026-08-22T06:15:09+00:00"
}Accepted reason codes
| Code | Meaning |
|---|---|
repeated_auth_failure | Repeated authentication failures |
credential_guessing | Automated credential guessing |
suspicious_scan | Suspicious network scanning |
mail_auth_abuse | Suspicious mail authentication attempts |
ssh_auth_abuse | Suspicious SSH authentication attempts |
leak_trap_hit | Leak trap address contacted |
credential_leak_signal | Possible credential list abuse |
exposed_address_abuse | Abuse of monitored exposed address |
abuse_pattern | Abuse pattern detected |
web_sensitive_file_probe | Sensitive file probing over HTTP |
web_exploit_probe | Known exploit path probing over HTTP |
web_path_traversal | Path traversal attempted over HTTP |
web_auth_abuse | Suspicious web authentication attempts |
web_scanner_enumeration | Automated web path enumeration |
Rate limits and plain lists
Read endpoints allow 120 requests per minute per address; ingest allows 180 per minute. Exceeding a limit returns 429 with a Retry-After header. Plain-text blocklists are cached for five minutes:
GET https://abuse.secureinsight.my/blocklists/10days.txt GET https://abuse.secureinsight.my/blocklists/15days.txt GET https://abuse.secureinsight.my/blocklists/30days.txt