Health
GET /health
no auth
Lightweight health check for load balancers. Does not query the database.
200 OK
Response
{
  "status": "healthy"
}
GET /api/health
no auth
API service identity and version.
200 OK
Response
{
  "status": "ok",
  "service": "threatrecall",
  "version": "1.0.0"
}
Recall (Public — No Auth)
These endpoints return only TLP:WHITE and TLP:GREEN nodes. Rate limited: 10 req/hour, 200 req/day per IP.
POST /api/public/demo-recall
no auth
Keyword search against the live demo workspace (APT29, FIN7, Lazarus). PII is rejected before search.
200 OK 400 PII / missing query 429 Rate limit
Parameter Type Description
query required string Natural language or keyword query. 1–300 chars. PII patterns rejected.
Request body
{
  "query": "APT29 Spear Phone"
}
Response
{
  "results": [
    {
      "id": "uuid",
      "node_type": "actor",
      "name": "APT29",
      "description": "...",
      "source": "stix:...",
      "tlp": "TLP:GREEN",
      "confidence": 0.85,
      "properties": {},
      "linked_evidence_ids": ["ev-uuid"]
    }
  ],
  "seeded": true,
  "query": "APT29 Spear Phone",
  "result_count": 1,
  "latency_ms": 42
}
Try it — live demo recall
STIX Export (Public — No Auth)
GET /api/public/demo-export.stix
no auth
Search demo workspace and return a STIX 2.1 bundle. Content-Type: application/stix+json;version=2.1.
Only TLP:WHITE and TLP:GREEN nodes included. Bundle validated against STIX 2.1 meta-schema (fail-closed: HTTP 422 on failure).
200 STIX 2.1 bundle 400 missing q 404 no results 422 validation failed 429 rate limit
ParameterTypeDescription
q required query string Search query, 1–300 chars
limit query integer Max results. Default 20, max 100.
Try it — live demo STIX export

Recall (Authenticated)
All recall endpoints require Authorization: Bearer <token>. Permission: recall:read. Results filtered to workspace TLP ceiling.
GET /api/recall/sessions/{id}
bearer
Get recall session metadata. Use node_ids to call /export.stix.
200 OK 404 not found
ParameterTypeDescription
id required pathUUIDRecall session ID
GET /api/recall/semantic
bearer
Pure embedding-based search. No keyword fallback.
ParameterTypeDescription
q requiredstringSearch query
limitintegerDefault 20, max 100
include_rejectedbooleanInclude rejected nodes
STIX Export (Authenticated)
GET /api/recall/sessions/{id}/export.stix
bearer
STIX 2.1 bundle for a recall session. Content-Type: application/stix+json;version=2.1.
TLP:RED enforcement: If session has TLP:RED nodes, workspace must have red_export_grant=true. Without it, returns HTTP 403.
200 STIX 2.1 bundle 403 RED export denied 404 not found 422 validation failed
ParameterTypeDescription
id required pathstringRecall session ID
STIX 2.1 bundle shape
{
  "type": "bundle",
  "id": "bundle--...",
  "spec_version": "2.1",
  "objects": [
    {
      "type": "malware",
      "spec_version": "2.1",
      "id": "malware--...",
      "created": "2024-01-15T00:00:00.000Z",
      "modified": "2024-01-15T00:00:00.000Z",
      "name": "CozyCar",
      "confidence": 85,
      "object_marking_refs": ["marking-definition--..."],
      "external_references": [...]
    }
  ]
}
Ingest
Direct STIX/OSINT/MISP/analyst/report ingest requires recall:write and the direct_ingest feature. LLM preview, staging review, batch lifecycle, and graph traversal require knowledge_graph. TLP values are normalized to canonical TLP:* markings before write/display.
POST /api/ingest/stix
bearer
Import STIX 2.1 bundle. Deduplicates by stix_id — safe to re-submit. Supported: indicator, malware, threat-actor, campaign, vulnerability, attack-pattern, course-of-action, intrusion-set.
201 created 400 missing bundle 402 feature unavailable
Request body
{
  "bundle": {
    "id": "bundle--4bd9e3a0-1234-5678-9abc-def012345678",
    "type": "bundle",
    "objects": [
      {
        "type": "malware",
        "id": "malware--a3c2b1d0-...",
        "name": "CozyCar",
        "description": "APT29 custom malware",
        "x_mitre_tlp": "GREEN",
        "confidence": 85,
        "created": "2024-01-15T00:00:00Z",
        "external_references": [{"source_name": "ThreatRecall"}]
      }
    ]
  },
  "default_tlp": "TLP:GREEN",
  "default_confidence": 0.7
}
Response
{
  "success": true,
  "results": {
    "nodes_created": 1,
    "evidence_created": 1,
    "skipped": 7
  }
}
POST /api/ingest/osint
bearer
Bulk-import OSINT collector feed. Node type is inferred from deterministic keyword classes when no explicit type is supplied (CVE/exploit, ATT&CK, actor, tool/malware, IOC, or generic OSINT).
201 created
Request body
{
  "collector": "alienvault-otx",
  "items": [
    {
      "title": "APT29 DNS tunneling indicator",
      "description": "Malicious DNS resolution",
      "url": "https://otx.alienvault.com/pulse/abc123",
      "type": "ioc",
      "tlp": "TLP:GREEN",
      "tags": ["apt29", "dns"]
    }
  ],
  "default_tlp": "TLP:AMBER",
  "default_confidence": 0.5
}
POST /api/ingest/misp
bearer
Parse MISP event JSON. MISP distribution 0 → TLP:RED, 1 → TLP:AMBER, others use default_tlp.
Request body
{
  "event": {
    "uuid": "abc123",
    "date": "2024-03-15",
    "Attribute": [
      {
        "uuid": "def456",
        "type": "md5",
        "value": "d41d8cd98f00b204e9800998ecf8427e",
        "to_ids": true,
        "category": "Payload delivery"
      }
    ]
  },
  "default_tlp": "TLP:AMBER",
  "default_confidence": 0.6
}
POST /api/ingest/analyst
bearer
Manual CTI entry from analyst notes.
Request body
{
  "nodes": [
    {
      "name": "OPNUM21",
      "node_type": "actor",
      "description": "Probing infrastructure observed Jan 2025",
      "tlp": "TLP:AMBER",
      "confidence": 0.75
    }
  ],
  "default_tlp": "TLP:GREEN",
  "default_confidence": 0.8
}
POST /api/ingest/preview
bearer
LLM-assisted entity extraction from raw text. Requires the knowledge_graph feature. Entities are staged for review; set ingest_mode=auto to commit immediately.
Request body
{
  "text": "APT29 used Cobalt Strike beacons with C2 at 198.51.100.42 delivered via macro-enabled Word documents.",
  "ingest_mode": "review"
}
Response
{
  "success": true,
  "batch_id": "batch-uuid",
  "summary": {
    "total_parsed": 3,
    "total_to_add": 2,
    "total_to_update": 0,
    "duplicates": 0,
    "missing_tlp": 1,
    "sensitive_warns": 0
  },
  "entities": [
    {
      "id": "staged-uuid",
      "status": "pending",
      "node_type": "actor",
      "name": "APT29",
      "proposed_tlp": "TLP:AMBER",
      "duplicate_candidates": [],
      "warnings": [],
      "extraction_reasoning": "..."
    }
  ],
  "auto_ingest": false
}
GET /api/ingest/batch/{id}
bearer
Get ingest batch metadata and all staged entities.
200 OK 404 not found
POST /api/ingest/batch/{id}/commit
bearer
Commit accepted staging records to kg_nodes. rejected records are discarded.
200 OK 404 not found
PATCH /api/ingest/staging/{id}
bearer
Accept, reject, merge, or mark uncertain a single staged entity.
FieldTypeDescription
status requiredenumpending | accepted | rejected | merged | uncertain
resolved_tlpstringOverride proposed TLP
merge_target_idUUIDRedirect entity to existing node (use with status=merged)
POST /api/ingest/report
bearer
Ingest structured report (parsed offline). Each content_block becomes an entity node.
Request body
{
  "title": "APT29 Campaign Report Q1 2025",
  "source_name": "internal-research",
  "content_blocks": [
    {
      "entity_name": "APT29",
      "node_type": "actor",
      "description": "Russian state APT group",
      "source_url": "https://internal/reports/apt29-q1",
      "excerpt": "APT29 conducted spear phishing..."
    }
  ],
  "default_tlp": "TLP:GREEN",
  "default_confidence": 0.6
}
Threat-intel ingestion and curation
External feeds are untrusted. Staging, provenance, license, warning-list, signature, and rollback gates apply before corpus mutation.
POST /api/threat-intel/feeds
bearer / API key
Register threat-intel feed source

Creates or updates a tenant-scoped STIX/TAXII feed source. Unknown redistribution terms fail closed.

201403
POST /api/threat-intel/batches
bearer / API key
Create staged threat-intel batch

Stages STIX 2.1 bundle, registered TAXII pull, or manual text input. Nothing is committed until the batch commit endpoint succeeds.

201403
POST /api/threat-intel/batches/{id}/commit
bearer / API key
Commit staged threat-intel batch

Atomically commits approved staged items into the tenant corpus with provenance and audit. Failed writes roll back the entire commit.

200403
POST /api/threat-intel/batches/{id}/revert
bearer / API key
Revert committed threat-intel batch

Removes objects created only by the batch and restores pre-existing merged objects from provenance snapshots.

200403
POST /api/threat-intel/warning-lists/{id}/lookup
bearer / API key
Look up indicator in active warning lists

Returns explicit absence when the tenant-owned or internally-derived lists contain no match.

200403
POST /api/threat-intel/correlation-candidates/{id}/promote
bearer / API key
Promote correlation candidate

Atomically promotes one pending candidate into an authoritative graph edge. Requires graph:write.

200403
POST /api/sirp/inbound
SIRP HMAC
Inbound SIRP disposition webhook

Receives signed vendor-neutral case dispositions. The signature covers method, path, endpoint id, event id, timestamp, tenant resolved from the endpoint, and raw-body digest.

202400401
Threat-agent APIs
All query paths are tenant/TLP scoped. Enrichment is corpus-only; graph traversal is bounded; scoring and STIX export fail closed on unknown lifecycle state.
POST /api/threat-agent/enrich
bearer / API key
Corpus-only threat agent enrichment

Looks up one normalized IOC against committed tenant corpus records only. Query-time provider calls are not performed. Unknown indicators return known:false rather than an error.

200400401403402
POST /api/threat-agent/enrich/batch
bearer / API key
Batch corpus-only threat agent enrichment

Looks up up to 100 normalized IOCs against committed tenant corpus records only. Per-item failures are isolated in the response.

200400401403402
POST /api/threat-agent/graph/pivot
bearer
Pivot a bounded threat-agent relationship graph

Returns the Spec 042 deterministic relationship graph payload for a visible pivot entity. The server resolves tenant, caller, feature gate, permission, and TLP clearance; unknown or above-clearance pivots return `known:false` without guessed alternatives.

200400401402403
POST /api/threat-agent/graph/export.stix
bearer
Export an exact threat-agent graph payload as STIX 2.1

Builds a STIX 2.1 bundle from the submitted Spec 042 payload only. The export does not re-query neighbors and does not add out-of-payload nodes or relationships.

200400401402403422
POST /api/threat-agent/scoring/sightings
bearer / API key
Record an indicator sighting

Records a true-positive, false-positive, or unknown indicator sighting through the shared REST/MCP/SIRP contract and queues deterministic lifecycle score refresh.

202400403
GET /api/threat-agent/scoring/scores/{indicator_ref}
bearer / API key
Read indicator lifecycle score

Returns the deterministic lifecycle score, export eligibility, and recomputable explanation. Unknown or above-clearance indicators return known:false rather than guessed content.

200403
POST /api/threat-agent/scoring/retractions
bearer / API key
Retract an indicator from lifecycle export eligibility

Records first-class indicator retraction state. Retraction forces export and default-enrichment exclusion within one refresh cycle regardless of score.

202400404
GET /api/threat-agent/scoring/export-set
bearer / API key
List current indicator export eligibility

Returns the tenant-scoped lifecycle export set snapshot. Unknown lifecycle state fails closed before STIX bundle construction.

200403
Audit
Audit logs are write-once — UPDATE and DELETE are blocked by DB trigger. Export requires audit:export (admin/audit role). Read requires audit:read.
GET /api/audit/export
admin/audit
CSV export of audit logs. Time range via from/to query params.
200 CSV download 403 audit:export required
ParameterTypeDescription
from querydate-timeStart time (ISO 8601)
to querydate-timeEnd time (ISO 8601)
limit queryintegerMax records. Default 1000, max 5000.
CSV shape
id,tenant_id,user_id,user_email,action,resource,resource_id,outcome,ip_address,metadata,created_at
"abc123","tenant-uuid","user-uuid","analyst@contoso.com","recall.search","recall","","success","192.168.1.1","{}","2024-01-15T12:00:00Z"
GET /api/audit/logs
admin/audit
Read audit log entries with optional filtering by user, time range, and pagination.
ParameterTypeDescription
user_id queryUUIDFilter by user
from querydate-timeStart time
to querydate-timeEnd time
limit queryintegerDefault 100
offset queryintegerDefault 0
Pilot (Public)
POST /api/pilot
no auth
Submit Design Partner Pilot application. Rate limited: 5 req/min per IP.
200 OK 400 validation error 429 rate limit
FieldTypeDescription
name requiredstringFull name (max 200 chars)
email requiredstringWork email
org requiredstringOrganization (max 200 chars)
role requiredenumcti-analyst | soc-manager | threat-intel-lead | security-engineer | ciso | other
cti_stackstringCurrent CTI stack (max 500 chars)
Request body
{
  "name": "Alex Chen",
  "email": "alex.chen@contoso.com",
  "org": "Contoso Security",
  "role": "threat-intel-lead",
  "cti_stack": "OpenCTI, Splunk, MISP"
}
Response
{ "success": true }

Looking for the integration compatibility matrix?

View Integrations Matrix →