Interface

API reference

v1 stable · v2 enveloped

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.

Reference

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.

Reference

Status codes

HTTP status codes returned by the API
CodeMeaning
200Success
201Ingest created a new indicator
400Invalid input; the message names the offending field
401Missing, unknown or disabled API key
404No such endpoint
405Wrong method; the Allow header lists the valid ones
413Request body exceeds the 8 KB limit
415Content-Type must be application/json
204Heartbeat accepted; no body returned
429Rate limited; honour the Retry-After header
503A dependency is unavailable; retry shortly
GET/api/v1/check?ip={address}auth: None (public)

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
  }
}
GET/api/v1/ip/{ip}auth: None (public)

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 }
}
GET/api/v1/feedauth: None (public)

Bulk 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
  }
}
GET/api/v2/statsauth: None (public)

Platform 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 }
  }
}
GET/api/v2/sensorsauth: None (public)

Collector 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 ..."
  }
}
POST/api/v2/sensors/heartbeatauth: Required - Authorization: Bearer <key>, or X-API-Key: <key>

Collector 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
POST/api/v1/eventsauth: Required - Authorization: Bearer <key>, or X-API-Key: <key>

Submit 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/events

Response

{
  "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"
}
Reference

Accepted reason codes

Accepted abuse reason codes
CodeMeaning
repeated_auth_failureRepeated authentication failures
credential_guessingAutomated credential guessing
suspicious_scanSuspicious network scanning
mail_auth_abuseSuspicious mail authentication attempts
ssh_auth_abuseSuspicious SSH authentication attempts
leak_trap_hitLeak trap address contacted
credential_leak_signalPossible credential list abuse
exposed_address_abuseAbuse of monitored exposed address
abuse_patternAbuse pattern detected
web_sensitive_file_probeSensitive file probing over HTTP
web_exploit_probeKnown exploit path probing over HTTP
web_path_traversalPath traversal attempted over HTTP
web_auth_abuseSuspicious web authentication attempts
web_scanner_enumerationAutomated web path enumeration
Reference

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