isMalicious Alerts API

Alerting trends and metrics

GitHub OpenAPI

Operations 3

GET /alerts/trends Get alert trends #
PATCH /alerts/{id} Set an alert's status #
GET /stream Alert stream (SSE) #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/ismalicious-com:ismalicious-com-alerts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

ismalicious-com-alerts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Ismalicious Com Alerts API
  version: 1.2.0
  contact:
    name: isMalicious Support
    url: https://ismalicious.com/support
    email: contact@ismalicious.com
  license:
    name: Proprietary
    url: https://ismalicious.com/terms
  description: 'Operations tagged alerts across 2 of this provider''s published API definitions: ismalicious-com-openapi.json, ismalicious-com-openapi2.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.ismalicious.com
  description: Production server
security:
- ApiKeyAuth: []
- BearerAuth: []
- BasicAuth: []
tags:
- name: Alerts
  description: Alerting trends and metrics
paths:
  /alerts/trends:
    get:
      tags:
      - Alerts
      operationId: getAlertTrends
      parameters:
      - name: days
        in: query
        description: Window in days (7-90, default 30)
        required: false
        schema:
          type: integer
          format: int64
      responses:
        '200':
          description: Opened/resolved per day plus MTTR percentiles for the signed-in scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlertTrendsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      summary: Get alert trends
      x-summary-source: derived
    servers:
    - url: https://api.ismalicious.com
      description: Production server
  /alerts/{id}:
    patch:
      tags:
      - Alerts
      summary: Set an alert's status
      description: '`OPEN`, `ACKNOWLEDGED` or `RESOLVED`, on one of your alerts (`GET

        /alerts`). Most alerts are per person: the write changes your copy only.


        A `cve.finding` alert of your organization and its Surveillance finding

        are one: `ACKNOWLEDGED` acknowledges an open finding, `RESOLVED` marks a

        finding that is not closed `PATCHED`, `OPEN` reopens one — for the whole

        organization, every member''s copy of the alert following, and

        `cve.finding.status_changed` is sent. When the finding does not move, the

        alert takes the finding''s status back (`finding` in the answer says which).

        With an API key the write is the organization''s automation: the finding

        names no person and the webhook carries `actor: "api"`; with a session it

        names you and says `actor: "user"`.'
      operationId: updateAlertStatus
      parameters:
      - name: id
        in: path
        description: The alert id (`GET /alerts`)
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAlertRequest'
        required: true
      responses:
        '200':
          description: The alert as the write left it, and for a `cve.finding` alert its finding
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateAlertResponse'
        '400':
          description: '`{"error": "Invalid status. Valid statuses are OPEN, ACKNOWLEDGED, RESOLVED."}`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: '`{"error": "Alert not found"}`: no alert of yours with this id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    servers:
    - url: https://api.ismalicious.com
      description: Production server
  /stream:
    get:
      tags:
      - Alerts
      summary: Alert stream (SSE)
      description: 'Your **new alerts**, as Server-Sent Events: the alerts of `GET /alerts`

        that belong to your current organization — the inbox of the session''s

        user, or of the organization''s owner for an API key, in the same JSON. An

        older alert filed under no organization, or under one you have left, is

        listed by `GET /alerts` and never streamed. Nothing else is streamed: no

        corpus-wide feed (that is TAXII), no single-check progress (that is

        `/check/stream`).


        **Plan.** Pro and Enterprise. Free and Basic get `403` with

        `error: "UPGRADE_REQUIRED"` and an offer (`cta`); a paid plan whose

        payment needs attention gets `403` with `error: "BILLING_ISSUE"`.

        **Cost.** Opening a stream never counts against the monthly request

        quota; the key''s burst limit applies.


        **Bounds.** At most 3 open streams per organization (`429`,

        `{"error": "Too many streams", "limit": 3}`, `Retry-After`); 30 minutes

        per connection, then `event: close` (`reason: max_duration`; also

        `unavailable` after three failed or timed-out reads, and `shutdown` when

        the server restarts, for a deploy: reconnect at once); a `: keep-alive`

        comment every 25 s; new alerts are read every 10 s, at most 100 a read,

        2 s behind the clock.


        **Wire format.** `event: connect` first, its `data` carrying

        `{"id":"connect","type":"connect","timestamp","data":{"details":{"organizationId","userId","filters","resumedFrom","maxDurationSeconds","pollSeconds","keepAliveSeconds"}}}`.

        Then one `event: alert` per alert, with `id: -`

        and `data: {"id": , "type": , "timestamp": ,

        "data": {"entity", "entityType", "severity", "details": }}`. `connect`, `reset` and `close` carry

        `id: -`, a bare position: where the stream started, or where its

        next read would have begun.


        **Resume.** Send the last `id` you received as `Last-Event-ID` (or

        `?lastEventId=`) — an alert''s, or the bare position of a `connect`,

        `reset` or `close`, so a client that received no alert still resumes

        without a gap: the stream replays what came after it, up to 24 hours

        back and 500 alerts. Past either, for an id this stream did not send, or

        for one dated in the future, it sends `event: reset` (`reason`:

        `cursor_expired`, `too_many_events`, `cursor_invalid`; `since`: where the

        replay starts), then the latest alerts of the window — catch up on the

        rest with `GET /alerts`. Delivery is at least once, in `createdAt` order

        within a read: each read looks back 30 s for rows committed late, and a

        resume from a `close` may repeat the alerts of its last 30 s, so

        deduplicate on `data.id`.'
      operationId: alertStream
      parameters:
      - name: types
        in: query
        description: 'Comma-separated alert event types (`threat.detected`,

          `reputation.changed`, `monitor.alert`, `cve.finding`, … — the

          `eventType` values of `GET /alerts`). Default: every type. An unknown

          type answers 400.'
        required: false
        schema:
          type: string
        example: threat.detected,reputation.changed
      - name: severity
        in: query
        description: 'Minimum severity: `low`, `medium`, `high` or `critical`. Default: every

          severity.'
        required: false
        schema:
          type: string
        example: high
      - name: lastEventId
        in: query
        description: 'Resume after this event id, for a client that cannot set the

          `Last-Event-ID` header (which wins when both are sent).'
        required: false
        schema:
          type: string
        example: 1762560000123456-ck9x2abc
      - name: Last-Event-ID
        in: header
        description: Resume after this event id
        required: false
        schema:
          type:
          - string
          - 'null'
      responses:
        '200':
          description: SSE stream — frame contract in the operation description
          headers:
            cache-control:
              schema:
                type: string
              description: Always `no-cache, no-transform`
            x-accel-buffering:
              schema:
                type: string
              description: Always `no` (disables proxy buffering)
          content:
            text/event-stream:
              schema:
                type: string
        '400':
          description: '`{"error": "unsupported_parameter", "parameter"}`: `categories` (an alert has none), an unknown type or severity'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: No valid API key or session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: 'Plan without the stream: `UPGRADE_REQUIRED` (Free, Basic) or `BILLING_ISSUE` (paid plan suspended), with a `cta`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: 'Three streams already open for the organization (`Retry-After: 30`), or the key''s burst limit'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: 'Alerts could not be read when the stream opened, or this server already holds as many streams as it serves (`Retry-After: 30`); retry with the same `Last-Event-ID`'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
      - ApiKeyAuth: []
      - BearerAuth: []
      - BasicAuth: []
    servers:
    - url: https://api.ismalicious.com
      description: Production server
components:
  schemas:
    ErrorResponse:
      type: object
      description: Error response. Some handlers return only `error`.
      required:
      - error
      properties:
        error:
          type: string
          description: Error type
          example: Bad Request
        message:
          type:
          - string
          - 'null'
          description: Detailed error message (not always present)
          example: 'Missing required parameter: query'
    UpdatedAlertFinding:
      type: object
      description: The finding a `cve.finding` alert moved (or left as it was)
      required:
      - id
      - status
      properties:
        id:
          type: string
          example: xfnd_9f2c1e
        status:
          type: string
          description: 'The finding''s status after the write: `OPEN`, `ACKNOWLEDGED`,

            `SNOOZED`, `PATCHED`, `FIXED`, `NOT_AFFECTED`, `ACCEPTED_RISK`'
          example: PATCHED
    AlertTrendsMttr:
      type: object
      description: MTTR percentiles in hours
      required:
      - avgHours
      - medianHours
      - p95Hours
      properties:
        avgHours:
          type: number
          format: double
        medianHours:
          type: number
          format: double
        p95Hours:
          type: number
          format: double
    AlertTrendsResponse:
      type: object
      description: GET /alerts/trends response (`api/alerts.rs::trends`)
      required:
      - days
      - bucket
      - timeSeries
      - mttr
      - totals
      properties:
        bucket:
          type: string
          description: Bucket size — always `day`
          example: day
        days:
          type: integer
          format: int64
          description: Effective window in days (clamped to 7-90)
        mttr:
          $ref: '#/components/schemas/AlertTrendsMttr'
        timeSeries:
          type: array
          items:
            $ref: '#/components/schemas/AlertTrendPoint'
        totals:
          $ref: '#/components/schemas/AlertTrendsTotals'
    AlertTrendPoint:
      type: object
      description: One day bucket of the alert trends time series
      required:
      - time
      - opened
      - resolved
      properties:
        opened:
          type: integer
          format: int64
          description: Alerts opened that day
        resolved:
          type: integer
          format: int64
          description: Alerts resolved that day
        time:
          type: string
          description: Day bucket start (RFC 3339)
          example: '2026-08-01T00:00:00+00:00'
    UpdateAlertRequest:
      type: object
      description: PATCH /alerts/{id} body (`api/alerts.rs::update_status`)
      required:
      - status
      properties:
        status:
          type: string
          description: '`OPEN`, `ACKNOWLEDGED` or `RESOLVED`'
          example: ACKNOWLEDGED
    AlertTrendsTotals:
      type: object
      description: Alert trends totals over the window
      required:
      - opened
      - resolved
      properties:
        opened:
          type: integer
          format: int64
        resolved:
          type: integer
          format: int64
    UpdateAlertResponse:
      type: object
      description: 'PATCH /alerts/{id} response: the alert as the write left it'
      required:
      - id
      - status
      properties:
        acknowledgedAt:
          type:
          - string
          - 'null'
        finding:
          oneOf:
          - type: 'null'
          - $ref: '#/components/schemas/UpdatedAlertFinding'
            description: '`null` unless the alert is a `cve.finding` alert of your organization'
        id:
          type: string
        resolvedAt:
          type:
          - string
          - 'null'
        status:
          type: string
          description: 'The alert''s status after the write. For a `cve.finding` alert it is

            the finding''s (`finding.status`), which may differ from the one asked

            for: « ACKNOWLEDGED » on a patched finding stays `RESOLVED`'
          example: ACKNOWLEDGED
        updatedAt:
          type:
          - string
          - 'null'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: Base64 encoded `apiKey:apiSecret`. Get your keys from https://ismalicious.com/app/account
    BasicAuth:
      type: http
      scheme: basic
      description: 'Username = apiKey, password = apiSecret. Legacy: any username, password = Base64(apiKey:apiSecret).'
    BearerAuth:
      type: http
      scheme: bearer
      description: '`Authorization: Bearer <token>` where token = Base64(apiKey:apiSecret) — the same credential as X-API-KEY.'
    sessionCookie:
      type: apiKey
      in: cookie
      name: __Secure-authjs.session-token
      description: Authenticated browser session. The claim endpoint also requires a verified email in the database; organization API keys cannot claim watches.
x-refined-from:
- ismalicious-com-openapi.json
- ismalicious-com-openapi2.json