Articles on: Features & Tools

APIs

Malanta API


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


Version 2.0 | July 2026



Contents




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


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


{
  "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


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


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


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



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


{ "indicator": "example.it" }


  • indicator — a domain, IP address, or email address to analyze


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


Step 2 — Poll for results


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


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


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


Example response


{
  "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
  • statusin_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.


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


↑ Back to top



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, and cluster membership. All endpoints use the base URL https://app.malanta.ai/data and follow the 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.


{
  "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.


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


{
  "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


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


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


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.


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


{
  "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


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


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


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


{
  "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


POST /v1/domains/certificates


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


↑ Back to top


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


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


{
  "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


POST /v1/domains/co-hosted-domains


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


↑ Back to top


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


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


{
  "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


POST /v1/domains/ip-ranges


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


↑ Back to top


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


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


{
  "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


POST /v1/domains/dns-records


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


↑ Back to top


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


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


{
  "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


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


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


{
  "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


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


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


{
  "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


POST /v1/fqdns/certificates


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


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


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


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


{
  "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


POST /v1/fqdns/dns-records


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


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


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.


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


{
  "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


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


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


{
  "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


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


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


{
  "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


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.


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


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


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


{
  "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


POST /v1/ips/reputation


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


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


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.


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


{
  "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


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



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


{
  "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


GET /v1/clusters/{cluster_id}


Retrieve a single cluster by its identifier.


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


{
  "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


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)


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


{
  "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


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


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


{
  "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


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


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


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.


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


{
  "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


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


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


{
  "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


POST /v1/certificates


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


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



STIX/TAXII Feed API


Retrieve general and targeted attack-infrastructure clusters in STIX 2.1 format over the TAXII 2.1 protocol.


This API uses Bearer token authentication (not the x-api-key header used by the other APIs).


Base URL: https://app.malanta.ai/feeds/taxii2


Authentication: Authorization: Bearer malanta_xxxxxxxxxxxxx


Endpoints


  • DiscoveryGET /feeds/taxii2/default
  • CollectionsGET /feeds/taxii2/default/collections
  • Get objectsGET /feeds/taxii2/default/collections/{collection_id}/objects


Query parameters


  • next — pagination cursor (returned in the previous response)


curl -s \
  -H "Authorization: Bearer malanta_xxxxxxxxxxxxx" \
  -H "Accept: application/json" \
  "https://app.malanta.ai/feeds/taxii2/default/collections/targeting-pre-attack-indicators/objects"


Paginated request


curl -s \
  -H "Authorization: Bearer malanta_xxxxxxxxxxxxx" \
  -H "Accept: application/json" \
  "https://app.malanta.ai/feeds/taxii2/default/collections/targeting-pre-attack-indicators/objects?next=eyJwYWdlX251bSI6MiwicGFnZV9zeiI6MTAwfQ"


STIX object types


The feed contains multiple STIX 2.1 object types:


  • indicator — pre-attack indicators with pattern expressions
  • infrastructure — attack-infrastructure elements (domains, IPs, certificates)
  • relationship — links between indicators, infrastructure, and threat actors
  • identity — targeted organizations and threat-actor identities
  • grouping — attack-infrastructure clusters grouping related objects


↑ Back to top



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/....

Updated on: 20/08/2026

Was this article helpful?

Share your feedback

Cancel

Thank you!