Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt

Use this file to discover all available pages before exploring further.

Consuming the AEGIS IoC feed

This guide walks a security engineer through end-to-end integration with the AEGIS IoC feed. You will authenticate, fetch the STIX 2.1 bundle, parse the Stix Domain Objects, ingest them into a downstream threat-intel pipeline, and schedule periodic refresh. If you are looking for the wire-format reference (bundle shape, indicator SDO fields, extension definition, confidence mapping), see /specifications/ioc-stix-mapping. This page is the runnable how-to.

What you’ll build

A pipeline that:
  1. Polls GET /v1/trust/iocs on a refresh cadence.
  2. Parses the returned STIX 2.1 bundle.
  3. Filters indicator SDOs by Mnemom IoC type (substrate_fingerprint, sha256, domain, url, technique_id).
  4. Ingests them into your downstream tool (MISP, OpenCTI, Anomali, ThreatConnect, custom).
  5. Resumes from the last-seen last_seen_at timestamp on subsequent polls.

Prerequisites

  • A Mnemom API key. If you don’t have one, see API keys and Authentication.
  • A STIX 2.1-aware downstream consumer. The Python stix2 library is the canonical reference implementation; install with pip install stix2.
  • A polling scheduler (cron, Kubernetes CronJob, Cloudflare Cron Triggers, etc.).

Step 1 — Fetch the bundle

Authenticate via the X-Mnemom-Api-Key header. The endpoint accepts three query parameters: type (single-IoC-type filter), after (ISO-8601 cursor matching last_seen_at), and limit (default 100, max 1000).
curl -sS \
  -H "X-Mnemom-Api-Key: $MNEMOM_API_KEY" \
  "https://api.mnemom.ai/v1/trust/iocs?limit=100"

Calm-at-GA expected output

At GA the network is calm by design (see calm-at-GA contract); a fresh fetch returns an empty objects array:
{
  "type": "bundle",
  "id": "bundle--<uuid>",
  "objects": []
}
This is the system telling the truth. Your pipeline should handle the empty case gracefully: log “0 new indicators” and move on.

Step 2 — Parse the SDOs

Pass the bundle through stix2.parse() and iterate over indicator SDOs.
Python
import stix2

bundle_obj = stix2.parse(bundle, allow_custom=True)

for obj in bundle_obj.objects:
    if obj.type != "indicator":
        continue

    # Extract canonical STIX fields
    indicator_id = obj.id
    confidence = obj.confidence           # 15 / 50 / 85
    valid_from = obj.valid_from
    pattern = getattr(obj, "pattern", None)  # absent for substrate_fingerprint / technique_id

    # Extract the Mnemom property-extension
    extensions = obj.extensions or {}
    mnemom_ext = extensions.get(
        "extension-definition--mnemom-aegis-2026-05",
        {},
    )
    mnemom_type = mnemom_ext.get("mnemom_type")
    mnemom_value = mnemom_ext.get("mnemom_value")
    mnemom_synthetic = mnemom_ext.get("mnemom_synthetic", False)
    mnemom_related_advisory = mnemom_ext.get("mnemom_related_advisory_id")

    # ... ingest into your downstream tool ...
Use allow_custom=True so the stix2 parser does not reject the Mnemom property-extension as unknown.

Step 3 — Map Mnemom IoC types into your tooling

Mnemom emits five IoC types. Two of them (substrate_fingerprint and technique_id) do not carry a STIX pattern; their value is in the mnemom_value extension field.
Mnemom IoC typeSTIX pattern presentWhere to read the value
sha256yes ([file:hashes.'SHA-256' = '<value>'])obj.pattern
domainyes ([domain-name:value = '<value>'])obj.pattern
urlyes ([url:value = '<value>'])obj.pattern
substrate_fingerprintnoobj.extensions[...].mnemom_value
technique_idnoobj.extensions[...].mnemom_value (maps to MITRE ATT&CK / MITRE ATLAS)
Filtering by type in the API call avoids loading types you don’t consume:
curl -sS \
  -H "X-Mnemom-Api-Key: $MNEMOM_API_KEY" \
  "https://api.mnemom.ai/v1/trust/iocs?type=substrate_fingerprint&limit=100"
The mnemom_synthetic boolean tells you whether the indicator is real (false) or synthetic seed (true). For production alerting, filter to mnemom_synthetic: false.

Step 4 — Subscribe to push updates (optional)

The poll path is the canonical integration. If you also want push-based notification on new IoC insertion, subscribe to the ioc.added webhook event: Push + poll together gives you near-real-time arrival plus a periodic full-state reconciliation. The poll path remains the source-of-truth for end-of-day reconciliation against your threat-intel platform.

Step 5 — Resume from where you left off

The endpoint orders results last_seen_at DESC. The recommended resume pattern is to track the most recent last_seen_at your pipeline has ingested and pass it as ?after= on the next call. When a response contains limit rows and more are available, the bundle carries a next_after extension at the bundle level:
{
  "type": "bundle",
  "id": "bundle--<uuid>",
  "objects": [ /* limit indicators */ ],
  "extensions": {
    "extension-definition--mnemom-aegis-2026-05": {
      "extension_type": "property-extension",
      "next_after": "2026-05-30T12:14:07Z"
    }
  }
}
Pass next_after as ?after= on the next request to paginate forward. STIX consumers that do not understand the extension ignore it; integrate the read in your own pipeline code.
Python — full pagination loop
def fetch_all_iocs(api_key: str, ioc_type: str | None = None, since: str | None = None):
    base = "https://api.mnemom.ai/v1/trust/iocs"
    headers = {"X-Mnemom-Api-Key": api_key}
    cursor = since

    while True:
        params = {"limit": 1000}
        if ioc_type:
            params["type"] = ioc_type
        if cursor:
            params["after"] = cursor

        response = requests.get(base, headers=headers, params=params, timeout=10)
        response.raise_for_status()
        bundle = response.json()

        for obj in bundle.get("objects", []):
            yield obj

        # Look for the bundle-level next_after extension to keep paginating.
        next_after = (
            bundle.get("extensions", {})
                  .get("extension-definition--mnemom-aegis-2026-05", {})
                  .get("next_after")
        )
        if not next_after:
            break
        cursor = next_after

Refresh cadence and rate limits

The endpoint is rate-limited to 1 request per second per IP (KV-backed; fail-open if the rate-limit KV namespace is unbound). Cloudflare Workers KV has a 60-second minimum TTL, so the effective practical bound is closer to 1 request per minute per IP. Recommended polling cadence: every 5–15 minutes via cron. The IoC publication rate at GA is very low (calm-at-GA contract); more frequent polling burns rate-limit budget without producing more signal. If your downstream tooling needs near-real-time updates, combine cron polling with the ioc.added webhook (Step 4).

No bundle-level cryptographic signing at GA

The STIX bundle is not cryptographically signed at GA. The IoC entries are produced from rows in the internal iocs table; the recipe-set envelope signing chain protects the Managed Rule pipeline, but the IoC bundle is a derived view.Customers wanting cryptographic attestation for cross-tenant detection content should rely on:

See also