> ## 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).

# APIs

# Malanta API

**Threats, Exposures & Prevented · IoPA Cluster · Gold Query (Enrichment) · STIX/TAXII Feed**

Version 2.0 | July 2026

---

## **Contents**

- [Overview](#2-overview)
  - [Base URLs](#3-base-urls)
- [Authentication](#2-authentication)
- [Platform API](#2-platform-api)
  - [Threats](#3-threats)
  - [Exposures](#3-exposures)
  - [Prevented](#3-prevented)
- [IoPA Cluster API](#2-iopa-cluster-api)
  - [Step 1 — Submit an indicator](#3-step-1-submit-an-indicator)
  - [Step 2 — Poll for results](#3-step-2-poll-for-results)
- [Gold Query API](#2-gold-query-api)
  - [Conventions](#3-conventions)
    - [Response envelope](#4-response-envelope)
    - [Indicator object](#4-indicator-object)
    - [Single lookups vs. batch](#4-single-lookups-vs-batch)
    - [Temporal parameters](#4-temporal-parameters)
    - [Pagination](#4-pagination)
    - [Domain vs. host scope](#4-domain-vs-host-scope)
    - [Errors](#4-errors)
  - [Domains](#3-domains)
    - [GET /v1/domains/{domain}/reputation](#4-get-v1domainsdomainreputation)
    - [POST /v1/domains/reputation](#4-post-v1domainsreputation)
    - [GET /v1/domains/{domain}/whois](#4-get-v1domainsdomainwhois)
    - [POST /v1/domains/whois](#4-post-v1domainswhois)
    - [GET /v1/domains/{domain}/certificates](#4-get-v1domainsdomaincertificates)
    - [POST /v1/domains/certificates](#4-post-v1domainscertificates)
    - [GET /v1/domains/{domain}/co-hosted-domains](#4-get-v1domainsdomainco-hosted-domains)
    - [POST /v1/domains/co-hosted-domains](#4-post-v1domainsco-hosted-domains)
    - [GET /v1/domains/{domain}/ip-ranges](#4-get-v1domainsdomainip-ranges)
    - [POST /v1/domains/ip-ranges](#4-post-v1domainsip-ranges)
    - [GET /v1/domains/{domain}/dns-records](#4-get-v1domainsdomaindns-records)
    - [POST /v1/domains/dns-records](#4-post-v1domainsdns-records)
    - [GET /v1/domains/{domain}/info](#4-get-v1domainsdomaininfo)
    - [GET /v1/domains/{domain}/profile](#4-get-v1domainsdomainprofile)
    - [GET /v1/domains/{domain}/code-repos](#4-get-v1domainsdomaincode-repos)
  - [FQDNs](#3-fqdns)
    - [GET /v1/fqdns/{fqdn}/certificates](#4-get-v1fqdnsfqdncertificates)
    - [POST /v1/fqdns/certificates](#4-post-v1fqdnscertificates)
    - [GET /v1/fqdns/{fqdn}/dns-records](#4-get-v1fqdnsfqdndns-records)
    - [POST /v1/fqdns/dns-records](#4-post-v1fqdnsdns-records)
    - [GET /v1/fqdns/{fqdn}/profile](#4-get-v1fqdnsfqdnprofile)
    - [GET /v1/fqdns/{fqdn}/code-repos](#4-get-v1fqdnsfqdncode-repos)
  - [IPs](#3-ips)
    - [GET /v1/ips/{ip}/info](#4-get-v1ipsipinfo)
    - [GET /v1/ips/{ip}/profile](#4-get-v1ipsipprofile)
    - [GET /v1/ips/{ip}/domains](#4-get-v1ipsipdomains)
    - [POST /v1/ips/domains](#4-post-v1ipsdomains)
    - [GET /v1/ips/{ip}/reputation](#4-get-v1ipsipreputation)
    - [POST /v1/ips/reputation](#4-post-v1ipsreputation)
    - [GET /v1/ips/{ip}/code-repos](#4-get-v1ipsipcode-repos)
  - [Clusters](#3-clusters)
    - [GET /v1/clusters](#4-get-v1clusters)
    - [GET /v1/clusters/{cluster_id}](#4-get-v1clustersclusterid)
  - [Code Repos](#3-code-repos)
    - [GET /v1/code-repos/{owner}/{repo}/reputation](#4-get-v1code-reposownerreporeputation)
    - [GET /v1/code-repos/{owner}/reputation](#4-get-v1code-reposownerreputation)
    - [POST /v1/code-repos/reputation](#4-post-v1code-reposreputation)
  - [Certificates](#3-certificates)
    - [GET /v1/certificates/{certificate_id}](#4-get-v1certificatescertificateid)
    - [GET /v1/certificates](#4-get-v1certificates)
    - [POST /v1/certificates](#4-post-v1certificates)
- [Profile API](#2-profile-api)
- [STIX/TAXII Feed API](#2-stixtaxii-feed-api)
- [Quick reference](#2-quick-reference)

---

## **Overview**

The Malanta API gives you programmatic access to pre-attack intelligence, exposure data, and threat enrichment for your monitored organizations and scopes.

There are four API families:

* **Platform API** — Retrieve imminent threats, exposures, and prevented items for your organization and scopes.
* **IoPA Cluster API** — Submit an indicator for pre-attack cluster analysis and retrieve the results.
* **Gold Query API** — Look up reputation and enrichment for any domain, host, IP, cluster, or certificate (WHOIS, certificates, co-hosted domains, hosting/ASN, DNS records, and more).
* **STIX/TAXII Feed API** — Retrieve attack-infrastructure clusters in STIX 2.1 format over the TAXII 2.1 protocol.

### **Base URLs**

| API family | Base URL |
| ---- | ---- |
| Platform API (Threats, Exposures, Prevented) | `https://app.malanta.ai/api` |
| IoPA Cluster API | `https://app.malanta.ai/api` |
| Gold Query API | `https://app.malanta.ai/data` |
| STIX/TAXII Feed API | `https://app.malanta.ai/feeds/taxii2` |

---

## **Authentication**

All requests require your Malanta API key. Keys are prefixed with `malanta_`. A missing or invalid key is rejected before the request reaches the service (`401`/`403`).

Most endpoints use the `x-api-key` header:

```
x-api-key: malanta_xxxxxxxxxxxxx
```

The **STIX/TAXII Feed API** is the only exception — it uses Bearer token authentication:

```
Authorization: Bearer malanta_xxxxxxxxxxxxx
```

Keep your API key private. Never expose it in frontend code, mobile apps, or public repositories.

---

## **Platform API**

The Platform API returns operational threats, exposures, and prevented items for a specific organization and scope. All three endpoints are paginated and share the same item structure.

### **Threats**

Returns a paginated list of imminent pre-attack threats.

**Endpoint:** `GET /v1/organizations/{organization_id}/scopes/{scope_id}/threats/page`

**Path parameters**

* `organization_id` — your organization identifier
* `scope_id` — the monitored scope identifier

**Query parameters**

* `PageSize` — items per page (e.g. 30)
* `PageNumber` — page number (1-indexed)

**Example request**

```bash
curl --request GET \
  --url 'https://app.malanta.ai/api/v1/organizations/{organization_id}/scopes/{scope_id}/threats/page?PageSize=30&PageNumber=1' \
  --header 'Accept: application/json' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'
```

**Example response**

```json
{
  "data": [
    {
      "exposure_id": "855eb38b-a9e0-402f-8cd6-186ee0b81481",
      "root_domain": "acme.com",
      "exposed_asset_name": "https://short.url/acme_com impersonates acme.com using a short URL service, redirecting to a malicious site and possibly used for malware delivery or phishing.",
      "exposed_asset_type": "Registered domain",
      "exposed_asset_identifier": "acme.com",
      "exposed_asset_status_timeline": [
        { "timestamp": 1767537152, "status": "Impersonated" }
      ],
      "exposure_type": "Malicious Domain",
      "exposure_scenario_category": "Domain Infrastructure Abuse",
      "exposure_scenario": "Short Url",
      "exposure_root_cause_name": "Short URL domain registration",
      "exposure_root_cause_identifier": "https://short.url/acme_com",
      "business_impact": {
        "impact_category": "Reputation Damage",
        "impact_summary": "..."
      },
      "attack_analysis": "...",
      "attack_infrastructure": {
        "clusters_ids": ["0474355E-6816-178C-4335-6556B264623F"],
        "status": "completed"
      },
      "exposure_attack_indicators": ["192.0.2.100"]
    }
  ],
  "total_count": 46,
  "page_size": 30,
  "page_number": 1,
  "has_next": true,
  "has_previous": false,
  "next_page": 2,
  "previous_page": null
}
```

**Response fields**

* `data` — array of items
* `total_count` — total number of items
* `page_size` / `page_number` — current pagination state
* `has_next` / `has_previous` — whether more pages exist
* `next_page` / `previous_page` — adjacent page numbers (or `null`)

**Item fields**

* `exposure_id` — unique identifier
* `root_domain` — the primary organizational domain being targeted
* `exposed_asset_name` — description of the exposed asset
* `exposed_asset_type` — Registered domain, Subdomain, or IP Address
* `exposed_asset_identifier` — the specific asset
* `exposed_asset_status_timeline` — status changes with timestamps
* `exposure_type` — classification (e.g. Malicious Domain)
* `exposure_scenario_category` / `exposure_scenario` — category and specific scenario
* `exposure_root_cause_name` / `exposure_root_cause_identifier` — root cause
* `business_impact` — impact category and summary
* `attack_analysis` — threat analysis narrative
* `attack_infrastructure` — associated cluster IDs and status
* `exposure_attack_indicators` — related indicators (IPs, domains)

Use `attack_infrastructure.clusters_ids` to pivot from a threat into the related pre-attack infrastructure clusters for deeper investigation.

[↑ Back to top](#2-contents)

### **Exposures**

Returns a paginated list of exposed assets for an organization and scope.

**Endpoint:** `GET /v1/organizations/{organization_id}/scopes/{scope_id}/exposures/page`

Path parameters, query parameters, response shape, and item fields are identical to the Threats endpoint.

**Example request**

```bash
curl --request GET \
  --url 'https://app.malanta.ai/api/v1/organizations/{organization_id}/scopes/{scope_id}/exposures/page?PageSize=30&PageNumber=1' \
  --header 'Accept: application/json' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'
```

[↑ Back to top](#2-contents)

### **Prevented**

Returns a paginated list of threats and exposures that have been prevented or remediated. Same pagination and item structure as Threats and Exposures.

**Endpoint:** `GET /v1/organizations/{organization_id}/scopes/{scope_id}/prevented/page`

To retrieve only the total count without the full list:

**Endpoint:** `GET /v1/organizations/{organization_id}/scopes/{scope_id}/prevented/count`

[↑ Back to top](#2-contents)

---

## **IoPA Cluster API**

Submit an indicator (domain, IP, or email address) for pre-attack cluster analysis, then poll for the results. This is a two-step asynchronous flow.

### **Step 1 — Submit an indicator**

**Endpoint:** `POST /v1/clusters/scan_iopa`

**Request body**

```json
{ "indicator": "example.it" }
```

* `indicator` — a domain, IP address, or email address to analyze

```bash
curl --request POST \
  --url 'https://app.malanta.ai/api/v1/clusters/scan_iopa' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx' \
  --data '{ "indicator": "example.it" }'
```

[↑ Back to top](#2-contents)

### **Step 2 — Poll for results**

**Endpoint:** `GET /v1/clusters/iopa/?indicator={indicator}`

* `indicator` — the indicator submitted in Step 1 (URL-encoded)

```bash
curl --request GET \
  --url 'https://app.malanta.ai/api/v1/clusters/iopa/?indicator=example.it' \
  --header 'x-api-key: malanta_xxxxxxxxxxxxx'
```

**Example response**

```json
{
  "clusters": [
    {
      "cluster_id": "A1B2C3D4-E5F6-7890-ABCD-EF1234567890",
      "presigned_url": "https://s3.amazonaws.com/..."
    }
  ],
  "raw_data": { "nodes": [], "relations": [] },
  "version": "1.0",
  "status": "completed"
}
```

**Response fields**

* `clusters` — array of clusters, each with a `cluster_id` and a `presigned_url`
* `raw_data` — graph data with `nodes` and `relations`
* `status` — `in_progress` or `completed`

While `status` is `in_progress`, poll the GET endpoint every 10 seconds until it becomes `completed`.

**Downloading cluster data.** Download the full cluster data using the `presigned_url` from each cluster. These are pre-signed links that require no additional authentication.

```bash
curl --request GET --url '{presigned_url}'
```

[↑ Back to top](#2-contents)

---

## **Gold Query API**

A read-only enrichment API for domains, hosts, IPs, clusters, and certificates: reputation, WHOIS, certificates, co-hosted domains, hosting/ASN info, DNS records, cluster membership, and consolidated [Profile](#2-profile-api) lookups. All endpoints use the base URL `https://app.malanta.ai/data` and follow the [conventions](#3-conventions) below.

Reputation note: a verdict of `MALICIOUS` means the entity is flagged; `UNKNOWN` means "not flagged" — it is never a claim that an entity is benign.

### **Conventions**

The Gold Query API uses a single, consistent response format across every endpoint.

#### **Response envelope**

Every response is shaped as `{ data, query, meta, pagination }`:

* **`data`** — the payload (an object, an array, or `null` when there is no match).
* **`query.indicator`** — echoes the entity you queried (`null` on batch requests).
* **`meta`** — request metadata: `endpoint`, `generated_at`, and, on time-aware endpoints, a `coverage` window (`first_observed_at` / `last_observed_at`).
* **`pagination`** — always present; meaningful only on paginated collections.

```json
{
  "data": { "...": "endpoint-specific payload" },
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": {
    "endpoint": "/v1/domains/{domain}/reputation",
    "generated_at": "2026-06-24T10:53:59.016Z",
    "coverage": { "first_observed_at": "2023-06-24T00:00:00Z", "last_observed_at": "2026-05-18T00:00:00Z" }
  },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

#### **Indicator object**

A reference to an entity, used both in `query.indicator` and inside payloads.

| Field | Type | Notes |
| ---- | ---- | ---- |
| `type` | string | one of `domain-name`, `fqdn`, `ipv4-addr`, `ipv6-addr` |
| `value` | string | the normalized domain or IP |

#### **Single lookups vs. batch**

* **GET** — single-entity lookups (one domain, host, IP, cluster, or certificate).
* **POST** — batch lookups. Send a JSON body with 1–100 entities. Requests with a body must set `Content-Type: application/json`.

When resolving more than one entity, prefer the batch `POST` route. Batch responses return one entry per input, each with its own `indicator` (the top-level `query.indicator` is `null`).

#### **Temporal parameters**

Time-aware endpoints (WHOIS, certificates, co-hosted domains, DNS records, IP info, IP domains) accept:

| Param | Type | Default | Meaning |
| ---- | ---- | ---- | ---- |
| `since` | ISO-8601 | none | lower bound of the observation window |
| `until` | ISO-8601 | none | upper bound (exclusive) |
| `history` | boolean | `false` | return the full timeline instead of the current view |

With no temporal parameters you get the current/latest view. Batch (`POST`) routes are current-only. Passing `since` later than `until` returns `400`.

#### **Pagination**

Collection endpoints are cursor-paged:

| Param | Type | Default | Notes |
| ---- | ---- | ---- | ---- |
| `limit` | integer | 100 | page size, 1–1000 |
| `cursor` | string | none | pass back `pagination.next_cursor` from the previous page |

When more rows exist, `pagination.has_more` is `true` and `pagination.next_cursor` holds the token for the next page. To retrieve a full collection, loop while `has_more` is `true`, passing `next_cursor` as `?cursor=`.

#### **Domain vs. host scope**

* `/v1/domains/{domain}/*` routes are **registered-domain scoped**: `{domain}` must be a registrable domain such as `example.com` or `example.co.uk`. A subdomain (e.g. `www.example.com`) returns `422`.
* `/v1/fqdns/{fqdn}/*` routes accept **any host** (apex or subdomain) and return data for that exact host only.

Use `/v1/domains` when you know the input is a registrable domain — it validates that for you and exposes more resources (reputation, WHOIS, co-hosted domains). Use `/v1/fqdns` for a specific host, or when you don't know in advance whether a hostname is an apex or a subdomain.

#### **Errors**

Error responses are shaped `{ "detail": "...", "request_id": "..." }`.

| Status | When |
| ---- | ---- |
| `400` | invalid parameter (e.g. `since` > `until`, page size over the cap, malformed cursor, temporal param on a batch route, too many entities in a batch) |
| `401` / `403` | missing or invalid API key |
| `422` | malformed domain/IP, or a subdomain sent to a registered-domain route |
| `500` | internal error |
| `503` | service temporarily unavailable |
| `504` | upstream query timed out |

`data: null` (or an empty array) means "no data", not an error — only a non-2xx status is an error.

### **Domains**

Registered-domain-scoped lookups (`{domain}` must be a registrable domain).

#### **GET /v1/domains/{domain}/reputation**

Malanta's verdict for a registered domain: `verdict` and signal `labels`, a 0–1 `malicious_score` (with a `HIGH`/`MEDIUM`/`LOW` band), attributed `apt_names`, `ioc_sources`, `context`, and the clusters the domain belongs to.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain; a subdomain returns `422` |

Enums: `verdict` = `MALICIOUS` | `UNKNOWN`; `labels[]` = `IOPA` | `IOC`; band = `HIGH` | `MEDIUM` | `LOW`.

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "reputation": { "verdict": "MALICIOUS", "labels": ["IOPA", "IOC"], "malicious_score": 0.98, "malicious_score_band": "HIGH" },
    "apt_names": [],
    "ioc_sources": ["malanta", "blackweb"],
    "context": ["RedLine Stealer botnet C2 server"],
    "clusters": [
      { "cluster_id": "33b3f438-1a2b-4c3d-9e4f-5a6b7c8d9e0f", "member_count": 30, "joined_at": "2026-05-20T00:00:00Z", "reputation": { "malicious_score": 1.0, "malicious_score_band": "HIGH" } }
    ],
    "timestamps": { "first_observed_at": "2025-10-20T15:48:32.208Z", "last_classified_at": "2026-06-22T07:00:45.774Z", "last_observed_at": "2026-06-22T09:34:57.004Z" }
  },
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/reputation", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

For an `UNKNOWN` verdict, `malicious_score` is `null` and `apt_names` / `ioc_sources` / `context` / `clusters` are empty.

[↑ Back to top](#2-contents)

#### **POST /v1/domains/reputation**

Batch reputation for 1–100 registered domains. Returns one entry per input, each with its own `indicator`.

| Body field | Type | Notes |
| ---- | ---- | ---- |
| `domains` | array<string> | 1–100 registered domains |

```bash
curl -X POST "https://app.malanta.ai/data/v1/domains/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"domains": ["example.com", "example.org"]}'
```

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/whois**

The current WHOIS registration record. With a temporal parameter, an inline `history[]` of prior versions (newest first) is added. `data` is `null` if the domain has no registration record.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain |
| `since` / `until` / `history` | query | temporal | add the prior-version `history[]` |

Contact roles: `REGISTRANT`, `ADMINISTRATIVE`, `TECHNICAL`, `BILLING`.

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/whois" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "observed_at": "2026-05-18T01:40:59Z",
    "created_at": "2022-11-06T00:00:00Z",
    "updated_at": "2026-05-10T00:00:00Z",
    "expires_at": "2026-11-06T00:00:00Z",
    "registrar": { "id": "1479", "name": "Example Registrar, LLC", "whois_server": "whois.example-registrar.com", "url": "http://www.example-registrar.com" },
    "statuses": ["clientTransferProhibited"],
    "name_servers": ["ns1.example-dns.com", "ns2.example-dns.com"],
    "contacts": [
      { "role": "REGISTRANT", "name": "Privacy Service", "organization": "Example Privacy", "address": { "street": null, "city": "Phoenix", "state": "AZ", "postal_code": null, "country": "United States" }, "email": "abc@privacy.example", "email_local_part": "abc", "email_domain": "privacy.example", "phone": null, "fax": null }
    ]
  },
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/whois", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/domains/whois**

Batch WHOIS for 1–100 registered domains. Each entry is `{ indicator, whois }`, where `whois` is the full record or `null` when the domain has no registration record.

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/certificates**

Certificates linked to the exact domain. By default returns currently-valid certificates; `history` / `since` / `until` include expired and superseded certificates. Cursor-paged.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain |
| `since` / `until` / `history` | query | temporal | include expired/older certificates |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/certificates?limit=50" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "certificate_id": "94273995-fdaa-4b24-a1fd-e052e3520736",
      "serial_number": "120022056273139920459243120498800462479",
      "serial_hex": "6563e1df3819f6ecf349f25a7ddda3c54ea",
      "validity": { "not_before_at": "2026-06-11T22:22:58Z", "not_after_at": "2026-09-09T22:22:57Z" },
      "subject": { "common_name": "webdisk.example.com", "alternative_names": ["example.com", "mail.example.com", "www.example.com"] },
      "issuer": { "common_name": "YR1", "organization": "Let's Encrypt", "country": "US", "locality": null },
      "is_self_signed": false,
      "fingerprints": { "sha1": "90808e86a0d9…", "sha256": "b868eaa376c6d6b612c0fda6cabf6805e0d5e57e5a3201130ccfafc4e1afb81c" },
      "period": { "first_observed_at": "2026-06-12T00:00:00Z", "last_observed_at": "2026-06-14T08:42:39Z" }
    }
  ],
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/certificates", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": true, "next_cursor": "eyJvIjoiMjAyNi0wNi0xMSIsImMiOiI1ZDliMWU3YSJ9" }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/domains/certificates**

Batch certificates for 1–100 registered domains, grouped per input: `{ indicator, certificates: [...] }`.

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/co-hosted-domains**

Domains that share an IP with the queried domain, each with the linking `via_ip` and observation dates. Current associations by default; `history` / `since` / `until` widen to the full timeline. Cursor-paged.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain |
| `since` / `until` / `history` | query | temporal | widen to historical associations |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/co-hosted-domains" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    { "co_hosted_domain": { "type": "domain-name", "value": "co-tenant-a.example" }, "via_ip": { "type": "ipv4-addr", "value": "119.82.9.133" }, "first_observed_at": "2026-02-04T00:00:00Z", "last_observed_at": "2026-06-01T00:00:00Z" },
    { "co_hosted_domain": { "type": "fqdn", "value": "mail.co-tenant-b.example" }, "via_ip": { "type": "ipv4-addr", "value": "119.82.9.133" }, "first_observed_at": "2026-03-01T00:00:00Z", "last_observed_at": "2026-06-01T00:00:00Z" }
  ],
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/co-hosted-domains", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/domains/co-hosted-domains**

Batch co-hosted domains for 1–100 registered domains, grouped per input.

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/ip-ranges**

The IPs the domain is currently hosted on — one item per IP — each with its observed window and the network block it belongs to (start/end IP, CIDR, company, ASN, geo, type). Current-only. Cursor-paged.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/ip-ranges" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "ip": { "type": "ipv4-addr", "value": "13.226.34.51" },
      "first_observed_at": "2026-02-04T00:00:00Z",
      "last_observed_at": "2026-06-28T00:00:00Z",
      "ip_range": { "start_ip": "13.226.0.0", "end_ip": "13.226.255.255", "cidr": "13.226.0.0/16" },
      "company": { "name": "Amazon.com, Inc.", "domain": "amazon.com" },
      "asn": { "number": 16509, "org": "Amazon.com, Inc.", "domain": "amazon.com" },
      "ip_type": "HOSTING",
      "geo": { "country": "US" }
    }
  ],
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/ip-ranges", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/domains/ip-ranges**

Batch for 1–100 registered domains, grouped per input: `{ indicator, ips: [...] }`.

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/dns-records**

Distinct DNS records observed for the exact domain — a flat array, one item per distinct `(record_type, value)`. Default returns each record type's latest resolution; `history` / `since` / `until` widen to the full timeline.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain |
| `record_type` | query | string | `A` or `CNAME` |
| `since` / `until` / `history` | query | temporal | include superseded records |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/dns-records" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    { "record_type": "A", "value": "203.0.113.10", "target": { "type": "ipv4-addr", "value": "203.0.113.10" }, "ttl": null, "period": { "first_observed_at": "2026-01-05T00:00:00Z", "last_observed_at": "2026-06-28T00:00:00Z" } }
  ],
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/dns-records", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/domains/dns-records**

Batch DNS records for 1–100 registered domains, grouped per input: `{ indicator, dns_records: [...] }`.

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/info**

A bounded overview of everything known about a domain. `summary` inlines a reputation headline (verdict + score); `available` is a set of existence flags telling you which other endpoints have data for this domain (`whois`, `certificates`, `clusters`, `dns_records`, `co_hosted_domains`, `ipinfo`, `code_repos`).

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain; a subdomain returns `422` |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/info" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "summary": { "reputation": { "verdict": "MALICIOUS", "malicious_score": 0.92, "malicious_score_band": "HIGH" } },
    "available": { "whois": true, "certificates": true, "clusters": true, "dns_records": true, "co_hosted_domains": false, "ipinfo": true, "code_repos": true },
    "first_observed_at": "2023-06-24T00:00:00Z",
    "last_observed_at": "2026-05-18T00:00:00Z"
  },
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/info", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/profile**

Consolidated current-state enrichment for a **registrable domain**: state, registration/WHOIS, network/ASN, DNS, open services, TLS (JARM + negotiated), web analysis (page / favicon / CSS / JS), tags, related observables, and intelligence attribution. Envelope is `{ data, query, meta }` (**no** `pagination`). Unknown entities still return **HTTP 200** with empty sections.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain; a subdomain returns `422` |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/profile" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

Full field reference, examples, and conventions: [Profile API - Integration Guide](https://help.malanta.ai/en/article/profile-api-integration-guide-1akmgbq/#3-get-v1domainsdomainprofile)

[↑ Back to top](#2-contents)

#### **GET /v1/domains/{domain}/code-repos**

Public source-code repositories in which the domain appears, grouped by repository — with the file/line hits in `evidence[]`, how the match was found (`occurrence`), and repository metadata (URL, stars, language). This is an exposure/attribution signal, not a verdict: a legitimate domain can appear in flagged repositories.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `domain` | path | string | registered domain; a subdomain returns `422` |
| `since` / `until` | query | ISO-8601 | window on when the match was discovered |
| `include_evidence` | query | boolean | default `true`; `false` omits `evidence[]` |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/domains/example.com/code-repos" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "repo": { "repo_id": "example-org/example-repo@master", "url": "https://github.com/example-org/example-repo", "platform": "github", "host": "github.com", "owner": "example-org", "stars": 1288, "forks": 143, "primary_language": "Python", "indicator_count": 12, "discovered_at": "2026-02-19T08:11:24.360Z", "last_observed_at": "2026-02-19T08:11:24.360Z" },
      "occurrence": { "seen_in": { "feed": true, "pivot": false }, "source_type": "feed", "feed_name": "urlhaus", "validation_status": "valid", "discovered_at": "2026-02-19T08:11:24.360Z" },
      "pivot": { "depth": 0, "method": null, "actor": null, "confidence": 1.0 },
      "evidence": [
        { "file": "config/hosts.txt", "line": 42, "snippet": "example.com" }
      ]
    }
  ],
  "query": { "indicator": { "type": "domain-name", "value": "example.com" } },
  "meta": { "endpoint": "/v1/domains/{domain}/code-repos", "generated_at": "2026-07-05T10:53:59.016Z" },
  "pagination": { "has_more": true, "next_cursor": "…" }
}
```

[↑ Back to top](#2-contents)

### **FQDNs**

Host-scoped endpoints. `{fqdn}` is an exact host (apex or subdomain, e.g. `www.example.com`).

#### **GET /v1/fqdns/{fqdn}/certificates**

Certificates linked to the exact host. Same shape and temporal/pagination behavior as the domain certificates endpoint. The queried host is echoed at `query.indicator` with `type: "fqdn"`.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `fqdn` | path | string | any well-formed host (apex or subdomain) |
| `since` / `until` / `history` | query | temporal | include expired/older certificates |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/fqdns/www.example.com/certificates" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "certificate_id": "94273995-fdaa-4b24-a1fd-e052e3520736",
      "serial_number": "120022056273139920459243120498800462479",
      "serial_hex": "6563e1df3819f6ecf349f25a7ddda3c54ea",
      "validity": { "not_before_at": "2026-06-11T22:22:58Z", "not_after_at": "2026-09-09T22:22:57Z" },
      "subject": { "common_name": "www.example.com", "alternative_names": ["www.example.com"] },
      "issuer": { "common_name": "YR1", "organization": "Let's Encrypt", "country": "US", "locality": null },
      "is_self_signed": false,
      "fingerprints": { "sha1": "90808e86a0d9…", "sha256": "b868eaa376c6d6b612c0fda6cabf6805e0d5e57e5a3201130ccfafc4e1afb81c" },
      "period": { "first_observed_at": "2026-06-12T00:00:00Z", "last_observed_at": "2026-06-14T08:42:39Z" }
    }
  ],
  "query": { "indicator": { "type": "fqdn", "value": "www.example.com" } },
  "meta": { "endpoint": "/v1/fqdns/{fqdn}/certificates", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/fqdns/certificates**

Batch certificates for 1–100 hosts, grouped per input: `{ indicator, certificates: [...] }`.

```bash
curl -X POST "https://app.malanta.ai/data/v1/fqdns/certificates" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"fqdns": ["www.example.com", "mail.example.com"]}'
```

[↑ Back to top](#2-contents)

#### **GET /v1/fqdns/{fqdn}/dns-records**

Distinct DNS records observed for the exact host — a flat array, one item per distinct `(record_type, value)`. Default returns each record type's latest resolution; `history` / `since` / `until` return the full timeline. `target` is a typed indicator (an IP for an `A`/`AAAA` record, a domain/host for a `CNAME`).

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `fqdn` | path | string | any well-formed host (apex or subdomain) |
| `record_type` | query | string | `A` or `CNAME` |
| `since` / `until` / `history` | query | temporal | include superseded records |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/fqdns/www.example.com/dns-records" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    { "record_type": "A", "value": "203.0.113.10", "target": { "type": "ipv4-addr", "value": "203.0.113.10" }, "ttl": null, "period": { "first_observed_at": "2026-01-05T00:00:00Z", "last_observed_at": "2026-06-28T00:00:00Z" } },
    { "record_type": "CNAME", "value": "proxy-ssl.webflow.com", "target": { "type": "fqdn", "value": "proxy-ssl.webflow.com" }, "ttl": null, "period": { "first_observed_at": "2025-07-12T06:30:36.822Z", "last_observed_at": "2026-06-28T00:00:00Z" } }
  ],
  "query": { "indicator": { "type": "fqdn", "value": "www.example.com" } },
  "meta": { "endpoint": "/v1/fqdns/{fqdn}/dns-records", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/fqdns/dns-records**

Batch DNS records for 1–100 hosts, grouped per input: `{ indicator, dns_records: [...] }`.

```bash
curl -X POST "https://app.malanta.ai/data/v1/fqdns/dns-records" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"fqdns": ["www.example.com", "mail.example.com"]}'
```

[↑ Back to top](#2-contents)

#### **GET /v1/fqdns/{fqdn}/profile**

Same consolidated Profile as the domain endpoint, scoped through an exact host (`{fqdn}`). Registration and related domain-scoped sections resolve at the apex / registrable domain.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `fqdn` | path | string | any well-formed host (apex or subdomain) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/fqdns/www.example.com/profile" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

Full field reference, examples, and conventions: [Profile API - Integration Guide](https://help.malanta.ai/en/article/profile-api-integration-guide-1akmgbq/#3-get-v1fqdnsfqdnprofile)

[↑ Back to top](#2-contents)

#### **GET /v1/fqdns/{fqdn}/code-repos**

Public source-code repositories an exact host appears in — same object and behavior as the domain code-repos endpoint, scoped to the host.

```bash
curl -X GET "https://app.malanta.ai/data/v1/fqdns/www.example.com/code-repos" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "repo": { "repo_id": "example-org/example-repo@master", "url": "https://github.com/example-org/example-repo", "platform": "github", "host": "github.com", "owner": "example-org", "stars": 1288, "forks": 143, "primary_language": "Python", "indicator_count": 5, "discovered_at": "2026-02-19T08:11:24.360Z", "last_observed_at": "2026-02-19T08:11:24.360Z" },
      "occurrence": { "seen_in": { "feed": true, "pivot": false }, "source_type": "feed", "feed_name": "urlhaus", "validation_status": "valid", "discovered_at": "2026-02-19T08:11:24.360Z" },
      "pivot": { "depth": 0, "method": null, "actor": null, "confidence": 1.0 },
      "evidence": [
        { "file": "config/hosts.txt", "line": 8, "snippet": "www.example.com" }
      ]
    }
  ],
  "query": { "indicator": { "type": "fqdn", "value": "www.example.com" } },
  "meta": { "endpoint": "/v1/fqdns/{fqdn}/code-repos", "generated_at": "2026-07-05T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

### **IPs**

#### **GET /v1/ips/{ip}/info**

A bounded overview of an IP: a `summary.reputation` headline (verdict + score), then an `available` object of existence flags (`hosted_domains`, `code_repos`, `clusters`), plus hosting, ownership, ASN, geo, and privacy-detection flags. `summary.reputation` and `available.clusters` come from the same signal as `GET /v1/ips/{ip}/reputation`. Enrichment fields are empty when the IP matches no known range; an un-enriched IP still returns its summary and flags. `first_observed_at` / `last_observed_at` are the IP's first-seen and most-recently-observed dates. `history` overlays the ownership-version timeline as `data.history[]`.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `ip` | path | string | IPv4/IPv6; malformed returns `422` |
| `since` / `until` / `history` | query | temporal | overlay version history |

```bash
curl -X GET "https://app.malanta.ai/data/v1/ips/8.8.8.8/info" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "summary": { "reputation": { "verdict": "MALICIOUS", "malicious_score": 0.83, "malicious_score_band": "HIGH" } },
    "available": { "hosted_domains": true, "code_repos": false, "clusters": true },
    "ip_range": { "start_ip": "8.8.8.0", "end_ip": "8.8.8.255", "cidr": "8.8.8.0/24" },
    "company": { "name": "Example Networks", "domain": "example-net.com" },
    "asn": { "number": 15169, "org": "EXAMPLE-AS", "domain": "example-net.com" },
    "ip_type": "HOSTING",
    "geo": { "country": "US" },
    "privacy": { "hosting": true, "proxy": false, "vpn": false, "tor": false, "relay": false, "service": null },
    "first_observed_at": "2024-01-15T00:00:00Z", "last_observed_at": "2026-06-20T00:00:00Z"
  },
  "query": { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" } },
  "meta": { "endpoint": "/v1/ips/{ip}/info", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **GET /v1/ips/{ip}/profile**

Consolidated current-state enrichment for an IP: tags, network (ASN / provider / address range / PTR), open-service probes (including failed probes with `error`), TLS (JARM + negotiated), related observables (shared hosting), and intelligence attribution. Unknown IPs return **HTTP 200** with empty applicable sections. Envelope is `{ data, query, meta }` (**no** `pagination`).

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `ip` | path | string | IPv4/IPv6; malformed returns `422` |

```bash
curl -X GET "https://app.malanta.ai/data/v1/ips/104.16.69.86/profile" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

Full field reference, examples, and conventions: [Profile API - Integration Guide](https://help.malanta.ai/en/article/profile-api-integration-guide-1akmgbq/#3-get-v1ipsipprofile)

[↑ Back to top](#2-contents)

#### **GET /v1/ips/{ip}/domains**

The domains hosted on an IP. `data` carries `total` (the IP's full hosted-domain count), `truncated` (true when we hold only a sample of a very dense IP), and a keyset-paginated `domains[]`, each entry with its own observed window.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `ip` | path | string | IPv4/IPv6 |
| `since` / `until` | query | ISO-8601 | narrow to domains whose window overlaps the range |
| `history` | query | boolean | every domain ever seen (current + past) |
| `limit` / `cursor` | query | paging | default 500, max 1000 |

```bash
curl -X GET "https://app.malanta.ai/data/v1/ips/8.8.8.8/domains" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "total": 21127,
    "truncated": true,
    "domains": [
      { "domain": { "type": "domain-name", "value": "a.example" }, "first_observed_at": "2025-05-17T00:00:00Z", "last_observed_at": "2026-07-01T00:00:00Z" },
      { "domain": { "type": "domain-name", "value": "b.example" }, "first_observed_at": "2026-01-12T00:00:00Z", "last_observed_at": "2026-06-20T00:00:00Z" }
    ]
  },
  "query": { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" } },
  "meta": { "endpoint": "/v1/ips/{ip}/domains", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": true, "next_cursor": "eyJkIjoiYi5leGFtcGxlIn0" }
}
```

Page until `pagination.has_more` is `false` to retrieve everything stored for the IP; check `truncated` to know whether that is still a subset of the IP's full total.

[↑ Back to top](#2-contents)

#### **POST /v1/ips/domains**

Batch hosted-domains for 1–100 IPs. One group per IP, with the same `total` / `truncated` / `domains` as the single route.

```bash
curl -X POST "https://app.malanta.ai/data/v1/ips/domains" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"ips": ["8.8.8.8", "1.1.1.1"]}'
```

[↑ Back to top](#2-contents)

#### **GET /v1/ips/{ip}/reputation**

Malanta's verdict for an IP. An IP that is a member of a malicious cluster is `MALICIOUS`; any other IP returns the `UNKNOWN` shape. The top-level `malicious_score` reflects the strongest cluster; `clusters[]` lists the malicious clusters the IP belongs to (strongest first).

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `ip` | path | string | IPv4/IPv6; malformed returns `422` |

```bash
curl -X GET "https://app.malanta.ai/data/v1/ips/203.0.113.7/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "reputation": { "verdict": "MALICIOUS", "labels": ["IOC"], "malicious_score": 0.16, "malicious_score_band": "LOW" },
    "apt_names": [],
    "ioc_sources": ["circl-misp-osint"],
    "context": [],
    "clusters": [ { "cluster_id": "5645115c-913f-550f-b179-b7366ef45bc6", "member_count": 8, "joined_at": "2026-02-01T00:00:00Z", "reputation": { "malicious_score": 0.16, "malicious_score_band": "LOW" } } ],
    "timestamps": { "first_observed_at": "2026-01-13T00:00:00Z", "last_classified_at": "2026-06-20T02:14:09.880Z", "last_observed_at": "2026-06-20T02:14:09.880Z" }
  },
  "query": { "indicator": { "type": "ipv4-addr", "value": "203.0.113.7" } },
  "meta": { "endpoint": "/v1/ips/{ip}/reputation", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/ips/reputation**

Batch IP reputation for 1–100 IPs. Returns one entry per input, each with its own `indicator`.

```bash
curl -X POST "https://app.malanta.ai/data/v1/ips/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"ips": ["203.0.113.7", "8.8.8.8"]}'
```

[↑ Back to top](#2-contents)

#### **GET /v1/ips/{ip}/code-repos**

Public source-code repositories an IP appears in — same object as the domain code-repos endpoint. This is an exposure signal, not a verdict.

```bash
curl -X GET "https://app.malanta.ai/data/v1/ips/8.8.8.8/code-repos" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "repo": { "repo_id": "example-org/example-repo@master", "url": "https://github.com/example-org/example-repo", "platform": "github", "host": "github.com", "owner": "example-org", "stars": 1288, "forks": 143, "primary_language": "Python", "indicator_count": 3, "discovered_at": "2026-02-19T08:11:24.360Z", "last_observed_at": "2026-02-19T08:11:24.360Z" },
      "occurrence": { "seen_in": { "feed": true, "pivot": false }, "source_type": "feed", "feed_name": "urlhaus", "validation_status": "valid", "discovered_at": "2026-02-19T08:11:24.360Z" },
      "pivot": { "depth": 0, "method": null, "actor": null, "confidence": 1.0 },
      "evidence": [
        { "file": "blocklists/ips.txt", "line": 120, "snippet": "8.8.8.8" }
      ]
    }
  ],
  "query": { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" } },
  "meta": { "endpoint": "/v1/ips/{ip}/code-repos", "generated_at": "2026-07-05T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

### **Clusters**

#### **GET /v1/clusters**

Every cluster an indicator belongs to. Pass `?indicator=` as an IP or a registrable domain; the type is auto-detected. The response `data` is an array of clusters.

You can also browse the collection without an indicator by passing `member_type` (`domain-name` or `ipv4-addr`) plus optional filters. Omitting both `indicator` and `member_type` returns `400`.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `indicator` | query | string | IPv4/IPv6 or registrable domain; omit for browse |
| `member_type` | query | enum | `domain-name` \| `ipv4-addr`; required on browse |
| `cluster_type` / `lifecycle` / `label` / `apt_name` / `ioc_source` | query | filters | repeatable |
| `malicious` / `verdict` / `confidence_band` / `malicious_score_band` / `since` / `until` / `include_members` / `limit` / `cursor` | query | filters + paging |  |

```bash
curl -X GET "https://app.malanta.ai/data/v1/clusters?indicator=8.8.8.8" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "cluster_id": "…",
      "cluster_class": { "value": "INFRASTRUCTURE" },
      "cluster_type": "HOSTED_DOMAIN_ROTATION_CLUSTER",
      "confidence": 0.92,
      "confidence_band": "HIGH",
      "lifecycle_status": "CONFIRMED",
      "member_count": 184,
      "members_truncated": false,
      "first_built_at": "2026-01-13T08:00:00Z",
      "last_updated_at": "2026-06-20T02:14:09Z",
      "reputation": { "verdict": "MALICIOUS", "malicious_score": 0.97, "malicious_score_band": "HIGH", "labels": ["IOC"] },
      "apt_names": [],
      "ioc_sources": ["malanta"],
      "members": [
        { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" }, "joined_at": "2026-05-20T00:00:00Z", "reputation": { "verdict": "MALICIOUS", "labels": ["IOC"] } }
      ]
    }
  ],
  "query": { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" } },
  "meta": { "endpoint": "/v1/clusters", "generated_at": "…" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

Pass `include_members=false` for a lighter listing without member detail.

[↑ Back to top](#2-contents)

#### **GET /v1/clusters/{cluster_id}**

Retrieve a single cluster by its identifier.

```bash
curl -X GET "https://app.malanta.ai/data/v1/clusters/{cluster_id}" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "cluster_id": "33b3f438-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
    "cluster_class": { "value": "INFRASTRUCTURE" },
    "cluster_type": "HOSTED_DOMAIN_ROTATION_CLUSTER",
    "confidence": 0.92,
    "confidence_band": "HIGH",
    "lifecycle_status": "CONFIRMED",
    "member_count": 184,
    "members_truncated": false,
    "first_built_at": "2026-01-13T08:00:00Z",
    "last_updated_at": "2026-06-20T02:14:09Z",
    "reputation": { "verdict": "MALICIOUS", "malicious_score": 0.97, "malicious_score_band": "HIGH", "labels": ["IOC"] },
    "apt_names": [],
    "ioc_sources": ["malanta"],
    "members": [
      { "indicator": { "type": "ipv4-addr", "value": "8.8.8.8" }, "joined_at": "2026-05-20T00:00:00Z", "reputation": { "verdict": "MALICIOUS", "labels": ["IOC"] } }
    ]
  },
  "query": { "indicator": null },
  "meta": { "endpoint": "/v1/clusters/{cluster_id}", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

### **Code Repos**

Reputation for public source-code repositories and the accounts (owners) that host them. Unlike the `.../code-repos` listing endpoints (which return the repositories an entity appears in), these score the repository or account itself: `verdict`, signal `labels`, a `malicious_score`, `ioc_sources`, `context`, and the account cluster it belongs to. Coverage today is GitHub; owner and repository names are case-insensitive. A verdict of `MALICIOUS` means the entity is flagged; `UNKNOWN` means "not flagged", never a claim that it is benign.

#### **GET /v1/code-repos/{owner}/{repo}/reputation**

Reputation for a single repository. `reputation`, `ioc_sources`, `context`, and `timestamps` describe the repository; `clusters[0]` describes its owner account (so an association-only repository can still carry a high cluster score contributed by a sibling repo). `member_count` is the number of flagged repositories under the account, and `clusters` is omitted when that count is 1. `apt_names` is currently always empty.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `owner` | path | string | account name; case-insensitive |
| `repo` | path | string | repository name (no owner prefix) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/code-repos/example-owner/example-repo/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "reputation": { "verdict": "MALICIOUS", "labels": ["IOPA"], "malicious_score": 0.76, "malicious_score_band": "HIGH" },
    "apt_names": [],
    "ioc_sources": ["urlhaus"],
    "context": [
      "reached via owner account 'example-owner' (pivot depth 1)",
      "pivoted from example-owner/seed-repo",
      "5 malicious indicators"
    ],
    "clusters": [
      { "cluster_id": "392841bf-7480-55b6-88fc-ca7b0a0d257c", "member_count": 2, "joined_at": "2026-07-25T16:56:03.236Z", "reputation": { "malicious_score": 1.0, "malicious_score_band": "HIGH" } }
    ],
    "timestamps": { "first_observed_at": "2026-07-25T16:56:03.236Z", "last_classified_at": "2026-07-25T16:56:03.236Z", "last_observed_at": "2026-07-25T16:56:03.236Z" }
  },
  "query": { "indicator": { "type": "code-repo", "value": "example-owner/example-repo" } },
  "meta": { "endpoint": "/v1/code-repos/{owner}/{repo}/reputation", "generated_at": "2026-07-30T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **GET /v1/code-repos/{owner}/reputation**

Account-wide verdict, folding in every flagged repository under the owner: `labels` and `ioc_sources` are unioned and `malicious_score` is the strongest repository's. Use this when you have identified the account but not the specific repository. `context` becomes an aggregate summary (one line per evidence class); for an account with a single flagged repository it reads the same as the per-repository route.

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `owner` | path | string | account name; case-insensitive |

```bash
curl -X GET "https://app.malanta.ai/data/v1/code-repos/example-owner/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "reputation": { "verdict": "MALICIOUS", "labels": ["IOPA", "IOC"], "malicious_score": 1.0, "malicious_score_band": "HIGH" },
    "apt_names": [],
    "ioc_sources": ["urlhaus"],
    "context": [
      "2 flagged repositories under this owner",
      "1 feed seed (urlhaus)",
      "1 reached via owner pivot (depth 1)",
      "pivoted from example-owner/seed-repo",
      "157 malicious indicators across 2 repositories"
    ],
    "clusters": [
      { "cluster_id": "392841bf-7480-55b6-88fc-ca7b0a0d257c", "member_count": 2, "joined_at": "2026-07-25T14:27:50.657Z", "reputation": { "malicious_score": 1.0, "malicious_score_band": "HIGH" } }
    ],
    "timestamps": { "first_observed_at": "2026-07-25T14:27:50.657Z", "last_classified_at": "2026-07-25T14:27:50.657Z", "last_observed_at": "2026-07-25T16:56:03.236Z" }
  },
  "query": { "indicator": { "type": "code-repo-owner", "value": "example-owner" } },
  "meta": { "endpoint": "/v1/code-repos/{owner}/reputation", "generated_at": "2026-07-30T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/code-repos/reputation**

Batch lookup for 1–100 entries, one group per input in request order. `repos` is a string array; scope is inferred per entry from the presence of a `/`: `example-owner/example-repo` is repository scope, `example-owner` is account scope. Each group echoes its own `indicator`, whose `type` (`code-repo` vs `code-repo-owner`) tells you which scope was applied. Deduped case-insensitively; one malformed entry rejects the whole request with `422`.

| Body field | Type | Notes |
| ---- | ---- | ---- |
| `repos` | array<string> | 1–100 `owner` or `owner/repo` entries |

```bash
curl -X POST "https://app.malanta.ai/data/v1/code-repos/reputation" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"repos": ["example-owner/example-repo", "other-owner", "unseen-owner"]}'
```

An unseen entry returns the `UNKNOWN` shape (`verdict: "UNKNOWN"`, empty labels/sources/clusters).

[↑ Back to top](#2-contents)

### **Certificates**

Look up a certificate directly by its own identifier — independent of the host-scoped certificate endpoints. The returned certificate object has the same shape.

#### **GET /v1/certificates/{certificate_id}**

A single certificate by its `certificate_id` (a case-sensitive UUID). Returns `404` if unknown.

```bash
curl -X GET "https://app.malanta.ai/data/v1/certificates/1D551315-126A-417F-AB3B-0E0CAAEED9BA" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": {
    "certificate_id": "1D551315-126A-417F-AB3B-0E0CAAEED9BA",
    "serial_number": "120022056273139920459243120498800462479",
    "serial_hex": "6563e1df3819f6ecf349f25a7ddda3c54ea",
    "validity": { "not_before_at": "2026-06-11T22:22:58Z", "not_after_at": "2026-09-09T22:22:57Z" },
    "subject": { "common_name": "www.example.com", "alternative_names": ["example.com", "www.example.com"] },
    "issuer": { "common_name": "YR1", "organization": "Let's Encrypt", "country": "US", "locality": null },
    "is_self_signed": false,
    "fingerprints": { "sha1": "90808e86a0d9…", "sha256": "b868eaa376c6d6b612c0fda6cabf6805e0d5e57e5a3201130ccfafc4e1afb81c" },
    "period": { "first_observed_at": "2026-06-12T00:00:00Z", "last_observed_at": "2026-06-14T08:42:39Z" }
  },
  "query": { "indicator": null },
  "meta": { "endpoint": "/v1/certificates/{certificate_id}", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **GET /v1/certificates**

Look certificates up by fingerprint or serial. Provide exactly one selector (otherwise `400`). `sha256` / `sha1` are unique; `serial_number` (decimal) and `serial_hex` (hex) can match several (cursor-paged).

| Param | In | Type | Notes |
| ---- | ---- | ---- | ---- |
| `sha256` | query | hex(64) | content hash |
| `sha1` | query | hex(40) |  |
| `serial_number` | query | decimal | decimal serial |
| `serial_hex` | query | hex | hex serial |
| `limit` / `cursor` | query | paging | see [Pagination](#4-pagination) |

```bash
curl -X GET "https://app.malanta.ai/data/v1/certificates?sha256=b868eaa376c6d6b612c0fda6cabf6805e0d5e57e5a3201130ccfafc4e1afb81c" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx"
```

```json
{
  "data": [
    {
      "certificate_id": "94273995-fdaa-4b24-a1fd-e052e3520736",
      "serial_number": "120022056273139920459243120498800462479",
      "serial_hex": "6563e1df3819f6ecf349f25a7ddda3c54ea",
      "validity": { "not_before_at": "2026-06-11T22:22:58Z", "not_after_at": "2026-09-09T22:22:57Z" },
      "subject": { "common_name": "www.example.com", "alternative_names": ["example.com", "www.example.com"] },
      "issuer": { "common_name": "YR1", "organization": "Let's Encrypt", "country": "US", "locality": null },
      "is_self_signed": false,
      "fingerprints": { "sha1": "90808e86a0d9…", "sha256": "b868eaa376c6d6b612c0fda6cabf6805e0d5e57e5a3201130ccfafc4e1afb81c" },
      "period": { "first_observed_at": "2026-06-12T00:00:00Z", "last_observed_at": "2026-06-14T08:42:39Z" }
    }
  ],
  "query": { "indicator": null },
  "meta": { "endpoint": "/v1/certificates", "generated_at": "2026-06-24T10:53:59.016Z" },
  "pagination": { "has_more": false, "next_cursor": null }
}
```

[↑ Back to top](#2-contents)

#### **POST /v1/certificates**

Batch certificate lookup — up to 100 lookups, mixed selector types allowed. Returns one group per requested `{type, value}`.

```bash
curl -X POST "https://app.malanta.ai/data/v1/certificates" \
  -H "x-api-key: malanta_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"lookups":[{"type":"sha256","value":"b868eaa3…"},{"type":"serial_number","value":"9223390981080069519"}]}'
```

[↑ Back to top](#2-contents)

---

## **Profile API**

Observable Profile endpoints return a single consolidated, current-state enrichment view for a domain, host, or IP.

* [GET /v1/domains/{domain}/profile](#4-get-v1domainsdomainprofile)
* [GET /v1/fqdns/{fqdn}/profile](#4-get-v1fqdnsfqdnprofile)
* [GET /v1/ips/{ip}/profile](#4-get-v1ipsipprofile)

Full details: [Profile API - Integration Guide](https://help.malanta.ai/en/article/profile-api-integration-guide-1akmgbq/)

[↑ Back to top](#2-contents)

---

## **STIX/TAXII Feed API**

[Malanta IOPA STIX/TAXII Feed - Integration Guide](https://help.malanta.ai/en/article/stixtaxii-feed-api-lsniel/)

[↑ Back to top](#2-contents)

---

## **Quick reference**

* Always send your API key: `x-api-key` for the Platform, IoPA Cluster, and Gold Query APIs; `Authorization: Bearer` for the STIX/TAXII Feed.
* Prefer the batch `POST` routes when resolving more than one entity (1–100 per call).
* `data: null` (or an empty array) means "no data", not an error — only a non-2xx status is an error.
* Treat `verdict: "UNKNOWN"` as "not flagged" — never as "benign".
* To page a collection, loop while `pagination.has_more` is `true`, passing `pagination.next_cursor` as `?cursor=`.
* Send a registrable domain to `/v1/domains/...`; send a specific host to `/v1/fqdns/...`.
* For a single consolidated enrichment view, use Profile (`/v1/.../profile`) — see [Profile API - Integration Guide](https://help.malanta.ai/en/article/profile-api-integration-guide-1akmgbq/).