Skip to content

IoC Lookup Guide ​

This guide explains how to use the Feedly API to resolve Indicators of Compromise (IoCs) into stable Feedly Entity IDs and retrieve their full relationships and metadata.

GET
POST

Authentication ​

Include your Bearer Token in the Authorization header:

json
"Authorization": "Bearer YOUR_ACCESS_TOKEN"

IoC Resolution Methods ​

There are two distinct ways to obtain the required Feedly Entity ID (nlp/f/entity/ioc:<uuid>) for an IoC before fetching its metadata.

MethodUse CaseEndpoint Used
Local GenerationRecommended for processing bulk lists of IoCs.None (Client-side)
AutocompleteBest for ad-hoc, one-off lookups.GET /v3/search/entities

πŸ’‘Tip: ​

  • Generating IDs locally is highly recommended at scale. It allows you to skip the Search API call entirely and jump straight to bulk metadata retrieval.

Canonicalization (Local Generation) ​

If generating an IoC identifier client-side using Python's uuid5, the raw IoC value must be canonicalized to ensure that variations resolve to the exact same identifier. Feedly uses the namespace a8d40c5d-8d04-4337-8866-4b93849886b8.

The canonicalization rules must be applied in this exact order:

RuleDescriptionExample
LowercaseThe value is fully lowercased.EVIL.COM βž” evil.com
De-obfuscationCommon obfuscation patterns are reversed.hxxps:// βž” https://
www[.]evil[.]com βž” www.evil.com
Trailing slash removalA single trailing / is stripped from the value.evil.com/path/ βž” evil.com/path
First-dot defangingThe first . in the value is replaced with [.].evil.com βž” evil[.]com

Best Practices ​

  • For bulk lookups, generate the UUIDs locally and pass up to 100 IDs to the POST /v3/entities/.mget endpoint.
  • When using the GET /v3/entities/{entityId} endpoint for a single lookup, you must URL-encode the entity ID (e.g., nlp/f/entity/ioc:123 becomes nlp%2Ff%2Fentity%2Fioc%3A123).

Example Request (Bulk Lookup) ​

Python

python
import re
import uuid
import requests

FEEDLY_NAMESPACE = uuid.UUID("a8d40c5d-8d04-4337-8866-4b93849886b8")
DOT_REGEX = re.compile(r"\.")

def canonicalize_ioc(ioc: str) -> str:
    ioc = ioc.lower()
    # De-obfuscate
    ioc = ioc.replace("hxxps://", "https://").replace("hxxp://", "http://").replace("[.]", ".").replace("(.)", ".")
    # Strip trailing slash
    ioc = ioc.rstrip("/")
    # First-dot defanging
    ioc = DOT_REGEX.sub("[.]", ioc, count=1)
    return ioc

def generate_ioc_id(ioc: str) -> str:
    canonical = canonicalize_ioc(ioc)
    return f"nlp/f/entity/ioc:{uuid.uuid5(FEEDLY_NAMESPACE, canonical)}"

# Generate IDs locally
iocs = ["evil.com", "codefusiontech.org", "1.2.3.4"]
entity_ids = [generate_ioc_id(ioc) for ioc in iocs]

# Fetch metadata in bulk
response = requests.post(
    "https://api.feedly.com/v3/entities/.mget",
    json=entity_ids,
    headers={"Authorization": "Bearer YOUR_ACCESS_TOKEN", "Content-Type": "application/json"}
)
print(response.json())

Example Response ​

JSON

json
{
  "label": "evil[.]com",
  "id": "nlp/f/entity/ioc:f113d828-d860-5348-b116-a63cca5fad19",
  "type": "indicatorOfCompromise",
  "aliases": [
    "evil.com"
  ],
  "popularity": 0.0,
  "hasSalience": true,
  "enterpriseFeatures": [
    "LeoSecurity"
  ],
  "relationships": {
    "actors": [],
    "cyberAttacks": [],
    "malwares": [
      {
        "count": 1,
        "entity": {
          "id": "nlp/f/entity/gz:mal:d29eb927-d53d-4af2-b6ce-17b3a1b34fe7",
          "label": "Emotet",
          "type": "malwareFamily"
        },
        "entryIds": [
          "RjSEndsJYbBtEC7p0r3kY3RsT9xWeibOdJ3fVxEAqiE=_19ccd18f49c:120597c:3c4cfc22"
        ],
        "firstMention": "2026-03-08T10:58:10.716000+00:00",
        "lastMention": "2026-03-08T10:58:10.716000+00:00"
      },
      {
        "count": 1,
        "entity": {
          "id": "nlp/f/entity/gz:mal:184f283e-3725-4c8b-a92e-475c794f6c2e",
          "label": "GlassWorm",
          "type": "malwareFamily"
        },
        "entryIds": [
          "hWtnRVXoXPNm5EDm3oP2jUequ286/VpsD+r8227sh04=_19cf36f7b2f:1373782:7d8a2c4"
        ],
        "firstMention": "2026-03-15T21:38:15.471000+00:00",
        "lastMention": "2026-03-15T21:38:15.471000+00:00"
      }
    ]
  },
  "iocDetails": {
    "type": "domain",
    "exports": 
      {
        "type": "stix2.1",
        "url": "["
      },
      {
        "type": "misp",
        "url": ""
      },
      {
        "type": "csv",
        "url": ""
      }
    ]
  }
}

πŸ” Troubleshooting ​

Error MessagePossible CauseSolution
400 Bad RequestPassing raw domains instead of Entity IDsEnsure you pass the full nlp/f/entity/ioc:<uuid> format to the .mget endpoint.
404 Not FoundEntity ID not URL-encodedURL-encode the entity ID (urllib.parse.quote) if passing it as a path parameter in a GET request.
403 ForbiddenInvalid or missing tokenVerify your Authorization header is using a valid Bearer token.
TimeoutMore than 100 IDs sent in a single .mget requestChunk requests into batches of ≀ 100 IDs client-side