Skip to content

Ingest a Report ​

Submit a publicly accessible intelligence report for automated extraction and ingestion. Babel fetches the URL, extracts entities and relationships using LLM analysis, enriches any indicators, and links the results into the existing knowledge graph.

All ingest endpoints require a key with the Intel Contributor role (or higher), and count against your monthly quota.

Submit a report ​

POST/ingestAuth required
Submit a report URL. The report itself is processed synchronously — the response is returned once it is saved.
ParameterTypeDescription
urlstringreqPublicly accessible URL of the report or advisory

Example request ​

bash
curl -X POST https://api.getbabel.io/ingest \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/threat-report.pdf" }'

Response shapes ​

The report itself is processed synchronously. Report links found inside it (up to 10) are queued and processed afterwards in the background, so they are not part of the response. The possible outcomes:

Success — new report processed:

json
{
  "success": true,
  "already_exists": false,
  "primary": {
    "report_id": "a3f2c8d1-...",
    "title": "MuddyWater targets Israeli organisations",
    "summary": {
      "source": "Kaspersky",
      "actors": 1,
      "clusters": 0,
      "campaigns": 0,
      "tools": 2,
      "ttps": 8,
      "cves": 1,
      "indicators": 12,
      "edges": 34,
      "historical_skipped": 0
    }
  },
  "depth_queued": 4,
  "depth1": [],
  "depth2": [],
  "already_existed": [],
  "failed": []
}

depth_queued is the number of linked report URLs queued for background processing. depth1, depth2, already_existed and failed are kept for backward compatibility and are always empty arrays.

Already ingested — URL was previously processed:

json
{
  "success": true,
  "already_exists": true,
  "title": "MuddyWater targets Israeli organisations",
  "url": "https://example.com/threat-report.pdf"
}

Fetch failed — the URL could not be retrieved:

json
{
  "success": false,
  "fetch_failed": true,
  "url": "https://example.com/threat-report.pdf",
  "tried": ["https://example.com/threat-report.pdf"],
  "error": "HTTP 403"
}

Not a single report — the page is a listing or archive of several reports:

json
{
  "success": false,
  "catalog_rejected": true,
  "url": "https://example.com/blog/"
}

Errors: 429 when the monthly quota is reached or the same URL is already being processed for you; 503 with a Retry-After header when the server is busy with other reports.

Streaming ingestion ​

POST/ingest/streamAuth required
Same as /ingest but uses server-sent events to stream progress updates in real time. Useful for UI integrations.

Text ingestion ​

POST/ingest/textAuth required
Submit raw report text instead of a URL. Use when the target page is behind a paywall or login.
ParameterTypeDescription
urlstringreqCanonical URL of the report (used for deduplication and provenance — the page does not need to be accessible)
textstringreqFull text content of the report (request body up to 5 MB)

On success, returns { "success": true, "already_exists": false, "data": { ... } }, where data holds the extracted entities. Linked reports are not followed for text submissions.

Babel is free for individual researchers, defenders, and analysts.