Appearance
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.
| Method | Use Case | Endpoint Used |
|---|---|---|
| Local Generation | Recommended for processing bulk lists of IoCs. | None (Client-side) |
| Autocomplete | Best 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:
| Rule | Description | Example |
|---|---|---|
| Lowercase | The value is fully lowercased. | EVIL.COM β evil.com |
| De-obfuscation | Common obfuscation patterns are reversed. | hxxps:// β https://www[.]evil[.]com β www.evil.com |
| Trailing slash removal | A single trailing / is stripped from the value. | evil.com/path/ β evil.com/path |
| First-dot defanging | The 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/.mgetendpoint. - 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:123becomesnlp%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 Message | Possible Cause | Solution |
|---|---|---|
400 Bad Request | Passing raw domains instead of Entity IDs | Ensure you pass the full nlp/f/entity/ioc:<uuid> format to the .mget endpoint. |
404 Not Found | Entity ID not URL-encoded | URL-encode the entity ID (urllib.parse.quote) if passing it as a path parameter in a GET request. |
403 Forbidden | Invalid or missing token | Verify your Authorization header is using a valid Bearer token. |
Timeout | More than 100 IDs sent in a single .mget request | Chunk requests into batches of β€ 100 IDs client-side |