Alerts in. Verdicts back. Notifications out.
Three edges to the platform: what sends you alerts, what tells you whether an indicator is bad, and where the result lands.
One endpoint, no mapping work on your side
POST /api/v1/ingest/alert reads the field names the
tools already use. A title is the only requirement, everything
else has a default.
# Send an alert from your SIEM to mlab IR $ curl -X POST https://ir.example.com/api/v1/ingest/alert \ -H "Authorization: token $IR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "title": "Beaconing to a known C2", "severity": "high", "product": "CrowdStrike Falcon", "dedup_key": "c2-beacon-ws-042", "observables": ["203.0.113.4", "evil.example.com"] }' HTTP/1.1 200 OK {"status": "created", "uuid": "f4c68182-...", "deduplicated": false} # Same call again, same dedup_key: no second alert. {"status": "duplicate", "uuid": "f4c68182-...", "ingest_count": 2}
| Field | Read from any of |
|---|---|
| title (required) | title, name, rule_name, rule.name, search_name, signature, alert_name, AlertName, subject |
| severity | severity, Severity, priority, level, urgency, risk, criticality |
| source | source, product, vendor, tool, ProductName, origin, integration |
| dedup_key | dedup_key, fingerprint, correlation_id, group_key |
| external_id | external_id, event_id, alert_id, SystemAlertId, sid, incident_id, id |
| observables | observables, iocs, indicators, artifacts |
Severity, understood
Words, P1 to P5, sev1 to sev5, and risk scores from 6 to 100. A number from 0 to 5 is deliberately not interpreted: Splunk numbers 1 as worst, others number 5 as worst, and guessing would file a P1 as low.
Batches that fail cleanly
Up to 200 per request. A batch returns 200 with a per-entry result even when some are rejected, so a sender retries only what failed instead of redelivering everything.
Limits, stated
1 000 alerts per minute per organisation, then 429 with Retry-After. 100 observables per alert. A deduplicated delivery does not count against your monthly quota.
Nine sources ship in the box
Every enabled source is asked at once and the answers merge into one verdict, with each source still readable underneath it. Keys are write-only: stored once, never sent back to a browser.
| Source | Covers | Free tier | Notes |
|---|---|---|---|
| mlab.sh | every routable type | Yes | On by default. The only source covering all nine types. |
| VirusTotal | ip, domain, url, hash | Yes | 4 requests/min, 500/day on a public key. |
| AbuseIPDB | ip | Yes | 1 000 checks/day. |
| GreyNoise | ipv4 | Yes | Community endpoint, 50 lookups/week. |
| urlscan.io | url, domain | Yes | Searches existing scans. Does not submit. |
| AlienVault OTX | ip, domain, url, hash | Yes | Pulse membership and attribution. |
| Shodan | ip | No | Host lookups need a paid membership. |
| MISP | ip, domain, url, email, hash | Yes | Your own instance. Needs an address. |
| Have I Been Pwned | No | Subscription-only breach API. |
Routing by type
A grid decides who answers for each kind of observable. Enabled means asked when an analyst presses Refresh. Automatic means asked the moment an observable is created. Two switches, because a rate-limited key is worth having for one and ruinous for the other.
Bring your own source
Any REST API that returns JSON: a URL template, an auth header, the types it covers, and JSON paths for the verdict, the score and each fact. The test button reports how many of those paths the response actually resolved, which is what separates a working mapping from one that silently reads nothing.
Cache and refresh
Six hours, per organisation, keyed on a hash of the lookup. Refresh bypasses and clears it. Failures are never cached, so correcting a key works immediately instead of after a wait.
Where the result lands
Events reach the channel a team already watches, rendered in that platform's own payload shape rather than as a wall of JSON.
Slack, Discord, Teams, or your own
Pick events from a catalog, or take a wildcard for a whole entity. A custom endpoint receives the raw event and can be signed with HMAC-SHA256 over the exact bytes sent, under X-IR-Signature.
Conditions, ANDed
A minimum severity, a text match on the title or the detail, and an option to ignore anything automation caused. A channel gets the subset it asked for, not everything.
Retries that make sense
Three attempts with backoff, retrying only what can succeed on a retry. A destination answering 301 is a configuration error, not a transient failure, and is not retried into the ground.
A delivery log
Every attempt is recorded: the event, the destination, the response, the outcome. When somebody says they never got the alert, there is an answer.
Wire your first detection rule in an afternoon.
Create an app token, point your SIEM at the ingest endpoint, done.