> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://help.malanta.ai/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Bring Your Own IOCs (beta)

# Bring Your Own IOCs — API Guide

Generate and retrieve threat intelligence reports programmatically, without the GUI.

---

## Authentication

All requests require an API key in the `x-api-key` header.

You can create and manage your API keys in the Malanta app under **Settings → API Keys**.

```bash
-H "x-api-key: malanta_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

The API key is tied to your organization — no org ID needed in requests.

---

## Base URL

```
https://app.malanta.ai/byoi/v1/byoi-report
```

---

## Endpoints

### 1. Generate a report

**POST** `/generate`

Submit a list of indicators (domains, IPs, emails) to start a report.

```bash
curl -s -X POST \
  "https://app.malanta.ai/byoi/v1/byoi-report/generate" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "indicators": ["evil-domain.com", "198.51.100.5"],
    "title": "Campaign Investigation",
    "report_date": "2026-04-04",
    "notify_email": "you@yourcompany.com"
  }'
```

**Request fields:**

| Field | Required | Description |
| ---- |
| `indicators` | Yes | List of domains, IPs, or emails (max 100) |
| `title` | No | Report title shown in results |
| `report_date` | No | IOCs discovery date (YYYY-MM-DD). Defaults to today. Used to calculate Malanta lead time. |
| `notify_email` | No | Email address to notify when the report is ready |

**Response:**

```json
{
  "report_id": "abc12345-...",
  "status": "processing",
  "created_at": "2026-04-04T12:00:00Z"
}
```

---

### 2. List your reports

**GET** `/`

List all reports in your organization, most recent first. Useful for dashboards, SIEM/SOAR sync jobs, or recovering lost `report_id` values without persisting them yourself.

```bash
# All reports
curl -s \
  "https://app.malanta.ai/byoi/v1/byoi-report" \
  -H "x-api-key: YOUR_API_KEY"

# Filter by status
curl -s \
  "https://app.malanta.ai/byoi/v1/byoi-report?status=completed" \
  -H "x-api-key: YOUR_API_KEY"
```

**Query parameters:**

| Field | Required | Description |
| ---- |
| `status` | No | Filter results by status. Allowed values: `processing`, `completed`, `failed`. Omit to return all reports. |

**Response:**

```json
{
  "total_count": 2,
  "data": [
    {
      "report_id": "b5879cd5-...",
      "status": "completed",
      "title": "Campaign Investigation",
      "indicator_count": 2,
      "report_date": "2026-04-04",
      "progress": 100,
      "progress_message": "Done.",
      "created_at": "2026-04-04T12:00:00Z",
      "completed_at": "2026-04-04T12:03:41Z",
      "download_html": "https://app.malanta.ai/byoi/v1/byoi-report/b5879cd5-.../download/html",
      "download_json": "https://app.malanta.ai/byoi/v1/byoi-report/b5879cd5-.../download/json"
    },
    {
      "report_id": "f12abc99-...",
      "status": "processing",
      "title": "Phishing Wave 042",
      "indicator_count": 18,
      "report_date": "2026-05-13",
      "progress": 44,
      "progress_message": "Pivoting on hosted infrastructure...",
      "created_at": "2026-05-13T08:55:01Z",
      "completed_at": null
    }
  ]
}
```

> **Note:** Each item has the same shape as the single-report status response (Endpoint 3). `download_html` and `download_json` only appear when `status = completed`.

---

### 3. Check report status

**GET** `/{report_id}`

Poll this endpoint until `status` is `completed` or `failed`.

```bash
curl -s \
  "https://app.malanta.ai/byoi/v1/byoi-report/abc12345-..." \
  -H "x-api-key: YOUR_API_KEY"
```

**Response when processing:**

```json
{
  "report_id": "abc12345-...",
  "status": "processing",
  "progress": 44,
  "progress_message": "Pivoting on hosted infrastructure...",
  "created_at": "2026-04-04T12:00:00Z"
}
```

**Response when completed:**

```json
{
  "report_id": "abc12345-...",
  "status": "completed",
  "title": "Campaign Investigation",
  "indicator_count": 2,
  "report_date": "2026-04-04",
  "progress": 100,
  "progress_message": "Done.",
  "created_at": "2026-04-04T12:00:00Z",
  "completed_at": "2026-04-04T12:03:41Z",
  "download_html": "https://app.malanta.ai/byoi/v1/byoi-report/abc12345-.../download/html",
  "download_json": "https://app.malanta.ai/byoi/v1/byoi-report/abc12345-.../download/json"
}
```

> **Note:** `download_html` and `download_json` only appear when `status = completed` and a report file was generated.

---

### 4. Download a report

**GET** `/{report_id}/download/html`
**GET** `/{report_id}/download/json`

Returns a redirect (302) to the report file. Use `-L` to follow it automatically.

```bash
# Download HTML report (interactive, viewable in browser)
curl -L \
  "https://app.malanta.ai/byoi/v1/byoi-report/abc12345-.../download/html" \
  -H "x-api-key: YOUR_API_KEY" \
  -o report.html

# Download STIX 2.1 bundle (JSON file in STIX 2.1 format)
curl -L \
  "https://app.malanta.ai/byoi/v1/byoi-report/abc12345-.../download/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -o report.stix.json
```

The HTML report is an interactive standalone page with cluster graphs and all investigation details.

The JSON download is a **STIX 2.1 Bundle** (JSON file) containing Indicator, Intrusion Set, Threat Actor, Attack Pattern, and Relationship objects. It can be imported directly into SIEM/SOAR platforms and threat intelligence tools that support the STIX standard.

Download links are **permanent** for the lifetime of the report (90 days). Each request generates a fresh signed URL internally.

---

## Full workflow (bash script)

```bash
#!/bin/bash
API_KEY="malanta_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE="https://app.malanta.ai/byoi/v1/byoi-report"

# Step 1: Submit
echo "Submitting report..."
REPORT_ID=$(curl -s -X POST "$BASE/generate" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "indicators": ["evil-domain.com", "198.51.100.5"],
    "title": "My Investigation"
  }' | python3 -c "import sys,json; print(json.load(sys.stdin)['report_id'])")

echo "Report ID: $REPORT_ID"

# Step 2: Poll until done
echo "Waiting for report..."
while true; do
  RESP=$(curl -s "$BASE/$REPORT_ID" -H "x-api-key: $API_KEY")
  STATUS=$(echo $RESP | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['status'], d.get('progress',''), d.get('progress_message',''))")
  echo "  $STATUS"
  if echo "$STATUS" | grep -q "completed\|failed"; then
    break
  fi
  sleep 30
done

# Step 3: Download if completed
DOWNLOAD_HTML=$(echo $RESP | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('download_html',''))")
DOWNLOAD_JSON=$(echo $RESP | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('download_json',''))")

if [ -n "$DOWNLOAD_HTML" ]; then
  echo "Downloading HTML report..."
  curl -L "$DOWNLOAD_HTML" -H "x-api-key: $API_KEY" -o "report-$REPORT_ID.html"
  echo "Saved: report-$REPORT_ID.html"
fi

if [ -n "$DOWNLOAD_JSON" ]; then
  echo "Downloading STIX 2.1 bundle..."
  curl -L "$DOWNLOAD_JSON" -H "x-api-key: $API_KEY" -o "report-$REPORT_ID.stix.json"
  echo "Saved: report-$REPORT_ID.stix.json"
fi
```

---

## Bulk-download workflow (using list)

```bash
#!/bin/bash
API_KEY="malanta_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
BASE="https://app.malanta.ai/byoi/v1/byoi-report"

# Get every completed report for your org
curl -s "$BASE?status=completed" -H "x-api-key: $API_KEY" \
  | python3 -c "
import sys, json
d = json.load(sys.stdin)
for r in d['data']:
    print(r['report_id'], r['download_json'])
" | while read REPORT_ID JSON_URL; do
  echo "Downloading STIX for $REPORT_ID..."
  curl -L "$JSON_URL" -H "x-api-key: $API_KEY" -o "report-$REPORT_ID.stix.json"
done
```

---

## Status values

| Status | Meaning |
| ---- |
| `processing` | Investigation is running (typically 2–10 minutes depending on the number and depth of indicators). Check `progress` (0–100) and `progress_message` for current stage. |
| `completed` | Done. Download links are available if findings were produced. |
| `failed` | Something went wrong. Retry with different or fewer indicators. |

---

## Error responses

| HTTP Code | Meaning |
| ---- |
| `400 Bad Request` | Invalid request body — check your indicators list or email format. Invalid indicators are returned in the `invalid_indicators` field. |
| `401 Unauthorized` | API key not recognized |
| `403 Forbidden` | Invalid or missing API key |
| `404 Not Found` | Report ID does not exist or belongs to another organization |
| `422 Unprocessable Entity` | Invalid query parameter — e.g. `status` is not one of `processing`, `completed`, `failed` |
| `503 Service Unavailable` | Report generation service temporarily unavailable — retry in a few minutes |

---

## Things to know

* **Indicator limit:** Up to 100 indicators per report
* **Indicator validation:** Each indicator must be a valid domain, IPv4, IPv6, or email address. Invalid indicators are rejected with a 400 error listing which ones failed.
* **Report retention:** Reports are automatically deleted after 90 days
* **Email notifications:** Optional — provide `notify_email` and you'll receive an email when the report is ready
* **Lead time:** Calculated from the `report_date` you provide. Shows how far ahead Malanta detected the attack infrastructure compared to when the IOCs were first observed.
* **API key scope:** Your API key is tied to your organization. You can only access reports generated by your organization. The list endpoint only ever returns reports owned by your org.
* **List ordering:** Reports are returned most-recent-first by `created_at`. No pagination — all of your org's reports are returned in one response.
* **STIX 2.1 output:** The JSON download is a STIX 2.1 Bundle containing Indicator, Intrusion Set, Threat Actor, Attack Pattern, and Relationship objects. Compatible with SIEM, SOAR, and threat intelligence platforms.