SOAR and API integration¶
How to submit indicators to Suspicious from a script or a SOAR playbook, wait for the verdict, and get a result ready to paste into a ticket. Every call is a plain HTTPS request with a token; the full request and response schemas are in the REST API reference and, on a running instance, at /api/docs/ (Swagger) and /api/schema/ (OpenAPI).
In the examples, $HOST is your Suspicious URL and $TOKEN is the token from the next section.
1. Get a token¶
Two ways:
- Long-lived key for an automation (recommended). In the Django admin, open Profiles → API Keys → Add, pick the user the automation runs as and an expiry (30 days up to 2 years). The raw token is shown once, so copy it immediately. Deleting the API key revokes the token.
- Login (interactive scripts).
POST /api/auth/login/with{"username": "...", "password": "..."}returns{"token": "...", "expiry": "...", "user": {...}}. These tokens last 10 hours, and login is limited to 5 attempts per minute.
Send the token on every request:
curl -H "Authorization: Token $TOKEN" "$HOST/api/auth/me/"
/api/auth/me/ returns the account and its groups; use it to check the token works.
2. Submit¶
All submissions create a case and return immediately; the analysis runs in the background.
| What | Request |
|---|---|
| A URL | POST /api/submit/url/ with {"url": "https://example.test/x", "context": "optional note"} |
| An IP or a hash | POST /api/submit/other/ with {"value": "203.0.113.7"} |
A file or an .eml |
POST /api/submit/file/ as multipart with a file field |
| A list of indicators | POST /api/submit/indicators/ with {"indicators": "one per line"}. At most 100 per submission; the list becomes one case with a verdict per indicator |
curl -X POST -H "Authorization: Token $TOKEN" -H "Content-Type: application/json" \
-d '{"url": "https://example.test/login", "context": "reported by SOC ticket 1234"}' \
"$HOST/api/submit/url/"
Response (HTTP 201 Created):
{"status": "success", "accepted": true, "submission_type": "url", "result_type": "case",
"case_id": 4521, "id": 4521, "message": "Submission accepted."}
If the indicator is on an allow list, no case is created: the answer is HTTP 200 with accepted: true, case_id: null and the message "Submission accepted (allowlisted, no case created)." Validation problems return HTTP 400 with {"status": "error", "code": "...", "detail": "..."}.
3. Wait for the verdict¶
Poll the case until its status is DONE (statuses: NEW, IN_PROGRESS, DONE, CHALLENGED):
curl -H "Authorization: Token $TOKEN" "$HOST/api/investigations/4521/"
The useful fields are status, result (SAFE, INCONCLUSIVE, SUSPICIOUS, DANGEROUS, ALLOW_LISTED, FAILURE), case_infos (score, confidence, verdict_explanation), threat_classification (what kind of threat, when known) and analysis_health (how many analyzers failed or are still running; a non-zero failed means the verdict has lower confidence). Poll every 10 to 30 seconds; how long a case takes depends on the analyzers that run for it.
This endpoint is for investigator accounts (the CERT and Admin groups). An account that is not an investigator can read only its own submissions at /api/submissions/<id>/.
4. Get a ticket-ready result¶
curl -H "Authorization: Token $TOKEN" "$HOST/api/submissions/4521/ticket/"
returns one flat payload meant to be copied into a ticket:
title,verdict(result,score,confidence,severity,tlp,pap,ai_classification,rationale),threat_classificationandanalysis_health,observables: each indicator with its own verdict and a link to its evidence,analyzer_summary(reports per verdict, analyzers that ran),recommended_action.
To create or update the matching TheHive alert from that payload, send POST to the same URL. It answers {"status": "created" or "updated", "alert_id": "...", "alert_url": "..."}. It needs the TheHive connector to be enabled and configured (409 otherwise), and it records who pushed in the alert and in the audit log.
5. Human-readable report¶
GET /api/cases/4521/report/ returns the case report as HTML (with screenshots), and GET /api/cases/4521/report.md returns the same verdict, explanation and per-indicator evidence as Markdown, for a ticket, a wiki page or a chat message. Both are downloads. In the web UI they are the Full report and Markdown buttons on a case. Text taken from outside (indicators, analyzer evidence, the reporter's words) is escaped in the Markdown, so it cannot create links or headings.
Limits and good practice¶
- Rate limit: 3000 requests per hour per user. Polling every 15 seconds uses 240 an hour per open case.
- Use one account per automation, so its activity is visible and its key can be revoked on its own.
- Idempotency: submitting the same indicator again reuses the earlier analysis where possible but still creates a new case.
- Errors: 401 means a missing or expired token, 403 a missing permission (not an investigator), 429 the rate limit.