Programmatic Access: ICDB Through the API

Everything the ICDB UI does is a REST call. Scope an API key, trade it for a Bearer JWT, and your SIEM, SOAR, or short Python script can query, ingest, and mutate the graph the same way your analysts do.


The UI is just a REST client

When an analyst clicks “Create cluster” in the ICDB web UI, what actually happens is a POST /api/v1/cluster/ with a session cookie. The UI is convenience; the API is the platform. Every node you can create, every query you can run, every detection you can publish has a stable REST endpoint behind it.

Which means if you want your SIEM to push enrichment back into ICDB nightly, or your SOAR to pull standing indicators every five minutes, you don’t need an integration plugin. You need an API key and a few lines of Python.

Five minutes to your first key

  1. Sign in as the user the integration should run as. Settings → API Keys.
  2. Click New API Key.
  3. Name it after what it does, like splunk-soar-enrichment, nightly-ioc-export, or terraform-bootstrap. Future-you will thank present-you.
  4. Pick the scopes. The narrowest set that lets the integration do its job. A read-only feed needs graph:read. A push-side integration needs graph:write. Detection authors get schema:read. The full scope list is below.
  5. Pick an expiration. 30 days for a dev key, 90 for production, 365 if you’re absolutely sure. Never-expire exists but you shouldn’t reach for it.
  6. Generate and copy both halves immediately. The secret is shown exactly once. Lose it and you start over.

A key has two parts. The client ID looks like ic_<32 hex chars> and identifies the key; it’s safe to log. The client secret is a base64url-encoded string that you treat like a password. You’ll pass both to the token endpoint and never write the secret in a request header directly.

The scopes that matter

ScopeWhat it unlocks
graph:readRead nodes, edges, clusters, investigations, ICQL queries
graph:writeCreate, update, delete graph data
schema:readRead graph schema definitions
schema:writeModify graph schema. Usually only admin tooling.
adminFull administrative access. Use sparingly, audit constantly.

Scope narrowly. A nightly export script does not need admin, and a key that holds admin is a key that lives in your incident response runbook.

Calling the API

Authentication is a two-step exchange. Trade your client ID + secret at POST /api/v1/auth/token/ for a short-lived (15-minute) Bearer JWT, then send the JWT on every request:

# 1. Exchange the API key for a JWT
TOKEN=$(curl -s -X POST https://ic.yourco.com/api/v1/auth/token/ \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type":    "client_credentials",
    "client_id":     "ic_…",
    "client_secret": "…"
  }' | jq -r .access_token)

# 2. Use it
curl -H "Authorization: Bearer $TOKEN" \
     "https://ic.yourco.com/api/v1/indicator/?kind=ip"

That’s it. Short-lived bearer tokens mean a leaked JWT expires on its own in 15 minutes; only the API key itself is long-lived, and the key never crosses the wire on data requests.

A short Python loop for proof-of-concept:

import os, requests

BASE       = "https://ic.yourco.com/api/v1"
CLIENT_ID  = os.environ["ICDB_CLIENT_ID"]      # ic_<32 hex>
CLIENT_SEC = os.environ["ICDB_CLIENT_SECRET"]  # base64url secret

# 1. Trade the API key for a Bearer JWT
tok = requests.post(f"{BASE}/auth/token/", json={
    "grant_type":    "client_credentials",
    "client_id":     CLIENT_ID,
    "client_secret": CLIENT_SEC,
}, timeout=10).json()
hdrs = {"Authorization": f"Bearer {tok['access_token']}"}

# 2. Pull every IP-typed indicator (the response is a JSON array)
r = requests.get(f"{BASE}/indicator/",
                 params={"kind": "ip"},
                 headers=hdrs, timeout=10)
r.raise_for_status()

for nbi in r.json():
    print(nbi["value"], nbi["kind"], nbi.get("tlp"))

That’s a working pull loop. Wrap it in a cron and your SIEM has the latest network indicators every morning before standup. Cache the JWT for fourteen minutes if you call the API on a tight cadence; it’s cheaper than re-exchanging the key on every request.

ICQL over the wire

The query language we walked through in Your First ICQL Query isn’t just a UI feature. POST /api/v1/graph/query accepts the same string the search bar does:

curl -X POST \
     -H "Authorization: Bearer $TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"query": "from nbi.value=\"malware.example.com\" limit 100"}' \
     https://ic.yourco.com/api/v1/graph/query

Response is the resolved subgraph as JSON: nodes, edges, and TLP-gated metadata. Anything an analyst can ask in the UI, a script can ask programmatically, with the exact same query syntax.

Status codes are the contract

The API returns standard HTTP and means it. 401 means the JWT is invalid, expired, or the key was revoked. 403 means the JWT is valid but lacks the scope for what you tried. 429 means you’re hitting a rate limit. 200 is shipped data; 201 is “I created what you asked.” Error bodies are a simple {"error": "..."} JSON object; read the message and check the status code.

Security hygiene that pays back the first time something goes wrong

  • One key per integration. Three integrations means three keys. Compromise of one doesn’t break the others.
  • Environment variables, not source. os.environ["ICDB_API_KEY"] in Python, process.env.ICDB_API_KEY in Node. Keys in repos get scraped within minutes by every bot on GitHub.
  • Rotate before they expire. Set 90-day expirations and rotate on day 75. Past the cliff is an outage; before the cliff is a no-op.
  • Watch last-used timestamps. Keys with no traffic in 60 days are a liability. Revoke them.
  • If something feels off, revoke first, investigate second. Revocation is immediate. Investigation is patient.

The point

ICDB is a platform first and a UI second. Anything you’d do by hand for ten minutes a day, you can automate. Anything you’d export to a CSV and email around, you can pipe through a script. Anything your SIEM already produces, you can fold back into the graph.

The full guides ship inside the app at Docs → API & Integration: separate walkthroughs for API Keys, Detection Import, Elastic integration, and Strelka integration. Open them when you’re ready to wire something real.