Authentication

Authenticated endpoints use API tokens for programmatic access. Most read endpoints are public and require no authentication.

API tokens

Create a personal API token from Settings. Tokens are prefixed with ioc_ and are shown only once on creation.

Include your token as a Bearer token in the Authorization header:

import requests

API_BASE = "https://iocget.com/api"
API_TOKEN = "ioc_your_token_here"

headers = {
    "Authorization": f"Bearer {API_TOKEN}"
}

response = requests.get(f"{API_BASE}/auth/me", headers=headers)
print(response.json())

Submissions

Submissions represent documents or URLs submitted for IOC extraction. Requires authentication to create; read endpoints are public.

Submit a file

POST /api/submissions/file Auth required

Upload a file for IOC extraction. Supported types: TXT, HTML, PDF, DOCX, DOC. Max 50 MB.

FieldTypeDescription
filemultipart/form-dataThe file to extract IOCs from
import requests

headers = {"Authorization": "Bearer ioc_your_token_here"}

with open("threat_report.pdf", "rb") as f:
    response = requests.post(
        "https://iocget.com/api/submissions/file",
        headers=headers,
        files={"file": ("threat_report.pdf", f, "application/pdf")}
    )

submission = response.json()
print(f"Submission ID: {submission['id']}, Status: {submission['status']}")

Response

{
  "id": "sub_abc123",
  "status": "pending",
  "source_type": "file_upload",
  "original_filename": "threat_report.pdf",
  "created_at": "2024-01-15T14:30:00Z"
}
Submissions are processed asynchronously. Poll GET /api/submissions/{id} until status is completed or failed. If the file was already submitted, the response includes "duplicate": true with the existing submission ID.

Submit a URL

POST /api/submissions/url Auth required

Submit a URL for IOC extraction. The content is fetched and analyzed automatically.

FieldTypeDescription
urlstringThe URL to fetch and extract IOCs from
import requests
import time

headers = {
    "Authorization": "Bearer ioc_your_token_here",
    "Content-Type": "application/json"
}

# Submit URL
response = requests.post(
    "https://iocget.com/api/submissions/url",
    headers=headers,
    json={"url": "https://example.com/threat-report"}
)
submission = response.json()
submission_id = submission["id"]

# Poll for completion
while True:
    result = requests.get(
        f"https://iocget.com/api/submissions/{submission_id}",
        headers=headers
    ).json()

    if result["status"] in ("completed", "failed"):
        break
    time.sleep(5)

print(f"Found {result['ioc_count']} IOCs")

List submissions

GET /api/submissions Public

List recent submissions, ordered by creation date descending. Supports incremental sync via the since parameter.

ParameterTypeDefaultDescription
limitinteger50Number of results (max 100)
offsetinteger0Pagination offset
sincestring—ISO 8601 UTC timestamp. Returns only submissions created or updated after it, oldest first. See incremental sync.
import requests

response = requests.get(
    "https://iocget.com/api/submissions",
    params={"limit": 20, "offset": 0}
)
submissions = response.json()

for sub in submissions:
    print(f"{sub['id']}: {sub['title'] or sub['source_identifier']} ({sub['ioc_count']} IOCs)")

Incremental sync

Use the since parameter to maintain a local mirror of all submissions without re-fetching the entire table on each run. When since is provided, the endpoint filters on updated_at and returns results oldest-first, so you capture both new submissions and changes to existing ones (status transitions, admin edits, etc.). Start from 1970-01-01T00:00:00Z, then pass the updated_at of the last record you received as since on the next call.

import requests

API_BASE = "https://iocget.com/api"

def sync_submissions(cursor: str | None = None) -> tuple[list, str | None]:
    """Fetch submissions updated after `cursor`. Returns (submissions, next_cursor)."""
    params = {"limit": 100}
    if cursor:
        params["since"] = cursor

    response = requests.get(f"{API_BASE}/submissions", params=params)
    response.raise_for_status()
    submissions = response.json()

    next_cursor = submissions[-1]["updated_at"] if submissions else cursor
    return submissions, next_cursor

# Initial full sync: start at the beginning and walk forward
all_submissions = []
cursor = "1970-01-01T00:00:00Z"
while True:
    batch, cursor = sync_submissions(cursor)
    if not batch:
        break
    all_submissions.extend(batch)
    if len(batch) < 100:
        break  # No more pages

# Later: incremental sync — pick up new and updated submissions
new_batch, cursor = sync_submissions(cursor)
print(f"Found {len(new_batch)} new/updated submissions")

For filtered search, use GET /api/submissions/search with optional q, status, and source_type query parameters.

Get a submission

GET /api/submissions/{submission_id} Public

Get full details for a submission, including all extracted IOCs.

import requests

submission_id = "sub_abc123"
response = requests.get(f"https://iocget.com/api/submissions/{submission_id}")
data = response.json()

print(f"Title: {data['title']}")
print(f"Status: {data['status']}")
print(f"IOC count: {data['ioc_count']}")

for ioc in data["iocs"]:
    print(f"  [{ioc['ioc_type']['name']}] {ioc['value']}")

Response

{
  "id": "sub_abc123",
  "title": "Threat Report Q1 2024",
  "summary": "Analysis of APT29 campaign targeting...",
  "status": "completed",
  "source_type": "file_upload",
  "original_filename": "threat_report.pdf",
  "ioc_count": 42,
  "iocs": [
    {
      "id": "ioc_xyz789",
      "value": "192.0.2.1",
      "refanged_value": "192[.]0[.]2[.]1",
      "ioc_type": { "name": "ipv4" },
      "context": "C2 server observed in network logs",
      "description": "C2 server",
      "created_at": "2024-01-15T14:30:00Z"
    }
  ],
  "created_at": "2024-01-15T14:28:00Z",
  "processed_at": "2024-01-15T14:30:00Z"
}

Export a submission

GET /api/submissions/{submission_id}/export Public

Export a completed submission in various formats.

ParameterValuesDescription
formatjson, csv, minimal (CSV of type and refanged value only), stix, ecs, mispExport format (default: json)
import requests

submission_id = "sub_abc123"

# Export as STIX 2.1
response = requests.get(
    f"https://iocget.com/api/submissions/{submission_id}/export",
    params={"format": "stix"}
)

with open("report.stix.json", "wb") as f:
    f.write(response.content)

# Export as CSV
response = requests.get(
    f"https://iocget.com/api/submissions/{submission_id}/export",
    params={"format": "csv"}
)
print(response.text)

Generate Sigma rules

POST /api/submissions/{submission_id}/sigma Auth required

Generate Sigma detection rules for a completed submission. Rules are built from the submission's IOCs and the original article, grouped into one rule per log source. They are AI-generated with status experimental: review and test them before deploying.

Generation usually takes 15–40 seconds and runs as a job. Pass wait to get the rules back in one call: the response is 200 with the finished job if it completes within wait seconds, otherwise 202 with a job to poll. Without wait the response is always 202. Results are kept for one hour. Limited to 10 requests per hour.

ParameterTypeDefaultDescription
waitinteger0Seconds to wait for the rules before returning a job to poll (max 90)
import requests
import time

headers = {"Authorization": "Bearer ioc_your_token_here"}
base = "https://iocget.com/api/submissions/sub_abc123/sigma"

job = requests.post(base, headers=headers, params={"wait": 60}).json()

# Still running after the wait: poll until it finishes
while job["status"] in ("pending", "processing"):
    time.sleep(3)
    job = requests.get(f"{base}/{job['job_id']}", headers=headers).json()

if job["status"] == "failed":
    raise RuntimeError(job["error"])

for rule in job["result"]["rules"]:
    print(f"{rule['title']} ({rule['level']})")

# All rules as one multi-document YAML file
with open("sigma_rules.yml", "w") as f:
    f.write(job["result"]["yaml"])

Response

{
  "job_id": "3f9c2a7e1b4d4c6f8e0a5b7d9c1e2f34",
  "status": "completed",
  "message": null,
  "elapsed_seconds": 18,
  "result": {
    "submission_id": "sub_abc123",
    "article_included": true,
    "rules": [
      {
        "title": "C2Looper C2 Network Connection",
        "level": "critical",
        "logsource": { "category": "network_connection", "product": "windows" },
        "yaml": "title: C2Looper C2 Network Connection\nid: d6ba803c-...\nstatus: experimental\n..."
      }
    ],
    "yaml": "title: C2Looper C2 Network Connection\n...\n---\ntitle: ..."
  }
}

status is one of pending, processing, completed or failed. result is present once completed and error once failed. article_included is false when the original article could not be retrieved (for example for file uploads); the rules are then based on the IOCs and summary only. If a job for the same submission is already running, the request returns that job instead of starting another.

Poll a Sigma job

GET /api/submissions/{submission_id}/sigma/{job_id} Auth required

Poll a Sigma generation job. Returns the same job object as above. Jobs are only visible to the user who started them and are kept for one hour; after that this returns 404.

IOCs

IOCs are deduplicated by value and type across all submissions. A single IOC can appear in multiple reports.

Supported IOC types

ipv4 ipv6 domain url hash_md5 hash_sha1 hash_sha256 hash_sha512 email cve filename command filepath asn ip_range ip_port registry_key

Search IOCs

GET /api/iocs/search Public

Search across all IOCs with optional filtering by value or type.

ParameterTypeDefaultDescription
qstring—Search query (partial match on value)
typestring—Filter by IOC type (e.g. ipv4, domain)
limitinteger50Number of results (max 100)
offsetinteger0Pagination offset
import requests

# Search for all IPv4 IOCs
response = requests.get(
    "https://iocget.com/api/iocs/search",
    params={"type": "ipv4", "limit": 100}
)
data = response.json()
print(f"Found {data['total']} IPv4 IOCs")

# Search by value
response = requests.get(
    "https://iocget.com/api/iocs/search",
    params={"q": "192.168", "type": "ipv4"}
)
for ioc in response.json()["iocs"]:
    print(f"{ioc['value']} — seen in {ioc['submission_count']} reports")

Response

{
  "total": 1240,
  "limit": 50,
  "offset": 0,
  "iocs": [
    {
      "id": "ioc_xyz789",
      "value": "malicious-domain.example.com",
      "refanged_value": "malicious-domain[.]example[.]com",
      "type": "domain",
      "context": "Observed in phishing campaign targeting...",
      "submission_id": "sub_abc123",
      "submission_count": 3,
      "created_at": "2024-01-15T14:30:00Z"
    }
  ]
}

Get an IOC

GET /api/iocs/{ioc_id} Public

Get full details for a specific IOC, including all submissions where it appears.

import requests

ioc_id = "ioc_xyz789"
response = requests.get(f"https://iocget.com/api/iocs/{ioc_id}")
ioc = response.json()

print(f"Value: {ioc['value']}")
print(f"Type: {ioc['ioc_type']['name']}")
print(f"First seen: {ioc['first_seen_at']}")
print(f"Seen in {ioc['submission_count']} reports:")
for sub in ioc["submissions"]:
    print(f"  - {sub['title'] or sub['source_identifier']}")

Stats

GET /api/iocs/stats Public

Get aggregate statistics: total IOC and submission counts, broken down by IOC type.

import requests

response = requests.get("https://iocget.com/api/iocs/stats")
stats = response.json()

print(f"Total IOCs: {stats['total_iocs']}")
print(f"Total reports: {stats['total_submissions']}")
print("\nBreakdown by type:")
for ioc_type, count in sorted(stats["iocs_by_type"].items(), key=lambda x: -x[1]):
    print(f"  {ioc_type}: {count}")

Response

{
  "total_iocs": 15820,
  "total_submissions": 342,
  "iocs_by_type": {
    "ipv4": 4210,
    "domain": 3890,
    "hash_sha256": 2540,
    "url": 1980,
    "hash_md5": 1430,
    ...
  }
}