Free tier monthly quota, no credit card. Sign up at portal.verdictiq.io.
QUICKSTART · 5 MINYour first verdict in 5 minutes.
One HTTPS call. The full signal set, the score, the recommended action. No agents, no migrations, no waiting on a vendor call.
3 prereqs · 5 steps · 1 production checklist. The page is linear, don't skip steps.
Three things, two minutes.
None of these need a contract or a sales call.
Generated in the portal under Settings → API Keys. Dev keys are scoped, rate-limited, revocable.
Anything that can POST JSON: curl, Postman, Python requests, Node fetch. Examples below cover four of them.
Generate an API key.
Dev key for tests, prod key for production. Don't ship the dev key.
Sign in at portal.verdictiq.io.
Open Settings → API Keys.
Click Create key and label it (local-dev, staging, prod-mssp-tenant-x). The label shows up in audit logs.
Copy the secret once. The portal won't show it again.
Dev keys default to a free-tier quota. See pricing if you expect more than the free monthly cap. View pricing
Make your first call.
One endpoint, one parameter. The same shape extends to bulk later.
Set $VERDICTIQ_API_KEY to the secret you just copied (format: sk_ followed by 64 hex chars). The example uses a public domain so the response is non-empty. Auth is sent via the X-API-Key header; the Authorization: ApiKey scheme is also accepted.
curl -X POST https://api.verdictiq.io/api/v2/ioc/enrich \
-H "X-API-Key: $VERDICTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"indicator":{"type":"domain","value":"example.com"}}'{
"indicator": {
"type": "domain",
"value": "example.com",
"normalized": "example.com"
},
"risk": {
"direction": "malicious",
"score": 38,
"strength": "medium",
"category": "..."
},
"signals": [
{
"signal_id": "newly_activated_domain",
"signal_name": "Newly-Activated Domain",
"signal_group": "dns_history",
"signal_subgroup": "domain_lifecycle",
"direction": "malicious",
"evidence": { "value": { "name": "first_seen", "type": "date", "value": "..." } }
},
"..."
],
"signal_count": 17,
"scores": {
"groups": { "...": "..." },
"families": { "...": "..." }
},
"recommended_actions": [
{ "action": "monitor_domain", "order": 1 }
],
"meta": {
"engine_version": "...",
"query_time_ms": 142,
"request_id": "..."
}
}Response above is truncated for clarity (full payload includes all signals, full scores breakdown, threat_context, and meta fields). The complete schema, per-field types and all enums live in the API reference.
We don't ship official SDKs yet. Generated clients from the OpenAPI spec are the recommended path.
Read the verdict.
Score, level, action, signals. Each field has one job.
{
"indicator": {
"type": "domain",
"value": "example.com",
"normalized": "example.com"
},
"risk": {
"direction": "malicious",
"score": 38,
"strength": "medium",
"category": "..."
},
"signals": [
{
"signal_id": "newly_activated_domain",
"signal_name": "Newly-Activated Domain",
"signal_group": "dns_history",
"signal_subgroup": "domain_lifecycle",
"direction": "malicious",
"evidence": { "value": { "name": "first_seen", "type": "date", "value": "..." } }
},
"..."
],
"signal_count": 17,
"scores": {
"groups": { "...": "..." },
"families": { "...": "..." }
},
"recommended_actions": [
{ "action": "monitor_domain", "order": 1 }
],
"meta": {
"engine_version": "...",
"query_time_ms": 142,
"request_id": "..."
}
}| Field · Type | What it means |
|---|---|
risk.scoreint · 0-100 (50 = neutral) | Numeric severity for the indicator. Higher is riskier. |
risk.direction · risk.strengthenum · malicious|safe|neutral · weak|medium|strong|very_strong | Bucketed score for branching. Direction first, strength second. |
recommended_actions[]array of action + order pairs | Pre-baked next steps, ordered by priority. SOAR-ready field. |
signals[]array of signal_id, signal_name, direction, signal_group, signal_subgroup, evidence | Every reason behind the score, with raw evidence. |
Plain-English rule: if risk_level is medium or higher, the analyst sees the signals; if it's low, the SOAR auto-resolves.
This is the abridged response. Full catalog (all signals, group/family taxonomy, schema) lives in the API reference.
Three endpoints. Different envelopes.
The verdict you just read is the per-IOC unit. Bulk wraps many of them in one call, item by item, same shape.
One IOC in, one verdict out. The exact response shape you just walked through (risk · signals · recommended_actions · meta).
Up to 10,000 IOCs in one call. Returns a wrapper of results[], took and record_count, where each result item has the same per-IOC shape as /enrich. Defaults to no signal_details (set top or all to include).
The per-IOC verdict shape (risk · signals · recommended_actions) is shared by /enrich and each item inside /enrich_bulk's results[].
Two failures, one retry loop.
Most calls that fail are auth (401) or rate-limited (429). Both recover with the loop below; the full error catalog lives in the API reference.
for attempt in range(3):
r = requests.post(...)
if r.status_code < 500:
break
time.sleep(2 ** attempt)Five checks before production.
None of these are optional; all of them save a 3 a.m. page.
Use a separate prod key. Audit logs split by key label.
Exponential, capped at 3 retries. Honor Retry-After on 429.
Same IOC, same hour, same verdict. Free-tier saves quota; paid-tier saves cents.
Sudden 401/403 means a key issue; 422 spikes mean upstream IOC malformation.
Soft cap warns at 80%, hard cap blocks. Don't find out at 100%.
You've got the verdict. Now wire it in.
Browse the full reference, or talk to the team that built it.
View pricing