# Digital Threat Monitoring Alerts **Sync Type: Incremental** ## Overview The Google Threat Intelligence (GTI) **Digital Threat Monitoring (DTM) Alerts** input collects alerts raised by Mandiant Digital Threat Monitoring — GTI's continuous monitoring of the open, deep, and dark web for references to **your own** organization, domains, brands, executives, and credentials. This is distinct from the [Threat List IOCs](./google-threat-intelligence-ioc) input. Threat List IOCs are indicators of compromise about threats in general; DTM alerts are findings about **your** assets: a leaked credential set, a lookalike domain registered against your brand, your data offered on a shop listing, a forum post naming your company. Each alert is emitted as an individual record, suited to a SIEM destination such as Microsoft Sentinel. ## Prerequisites ### 1. A Google Threat Intelligence subscription with DTM - Digital Threat Monitoring is included only with **GTI Enterprise** or **Enterprise Plus**. A standard GTI key that works for other inputs returns `403` here. - At least one **DTM monitor** must be configured in the GTI console. Alerts only exist for the monitors you have defined — a tenant with no monitors produces no alerts, regardless of licensing. ### 2. A GTI API key - The input authenticates with a GTI API key sent as the `x-apikey` header. - For unattended pipelines, use a **service account** API key. Service accounts are created by a GTI **group administrator** and are not tied to an individual, so they survive offboarding. ## API Key Setup 1. **Sign in to Google Threat Intelligence** (or have your group administrator do so). 2. **Retrieve an API key:** - *Personal key:* open the user menu (top right) or the left navigation → **API Key**, and copy the value under **Google Threat Intelligence API Key**. - *Service account key (recommended for pipelines):* a **group administrator** opens the user menu → **My Group** → **Members**, creates a service account, and copies its API key. 3. **Confirm the key is entitled to DTM.** A valid key without DTM licensing returns `403`, not `401`. 4. **Store the key securely** and provide it as the input's API Key secret. If you are migrating from the Mandiant Advantage API, note that the old public/private key pair and its OAuth2 token exchange are **not** used here. This input sends a single static GTI API key. Where a legacy integration expects a username and password, GTI's migration guidance is to use the literal `gti-user` as the key ID and your GTI API key as the secret. ## Configuration ### Settings | Setting | Type | Required | Default | Description | | ------- | ---- | -------- | ------- | ----------- | | `alert_types` | array of string | No | all | Only collect these DTM alert types. Leave empty to collect all of them. See [Alert Types](#alert-types). | | `statuses` | array of string | No | all | Only collect alerts in these workflow states. Leave empty to collect all of them. See [Alert Statuses](#alert-statuses). | | `severities` | array of string | No | all | Only collect alerts at these severities. Allowed values: `high`, `medium`, `low`. | | `mscore_gte` | int | No | - | Only collect alerts with an indicator mscore at or above this value (0-100). Leave unset for no mscore filter. | | `include_documents` | bool | No | `false` | Inline the matched document, labels, and topics on every alert. See [Document inlining and record size](#document-inlining-and-record-size) before enabling. | | `truncate` | int | No | - | Cap inlined document fields at this many characters. Has no effect unless **Include Documents** is on. | | `backfill_start_time` | date | No | - | The date to start fetching data from. If not specified, no past records will be fetched. | | `use_synthetic_data` | bool | No | `false` | Generate synthetic data for testing, instead of connecting to a real data source. | | `rate_limit` | object | No | - | Maximum outbound source-API request rate. A blank or zero value falls back to the connector's default rate-limiting behavior. Maximum 10 requests per second. See [API Rate Limiting](../../../guides/rate-limiting) for the field format. | ### Secrets | Secret | Type | Required | Description | | ------ | ---- | -------- | ----------- | | `api_key` | secret | Yes | GTI API key sent as the `x-apikey` header. Digital Threat Monitoring requires a Google Threat Intelligence Enterprise or Enterprise Plus licence. | ### Alert Types Leave **Alert Types** empty to collect everything, or narrow to the categories you act on. | Alert Type | What it means | |------------|---------------| | Compromised Credentials | Credentials belonging to your organization found exposed | | Domain Discovery | A newly observed domain resembling one of yours (typosquats, lookalikes) | | Forum Post | A forum post matching one of your monitors | | Message | A chat or messaging-platform post matching one of your monitors | | Paste | Content on a paste site matching one of your monitors | | Shop Listing | Your data or access offered for sale on a marketplace | | Tweet | A post on X/Twitter matching one of your monitors | | Web Content | Web page content matching one of your monitors | ### Alert Statuses DTM alerts carry a triage state that analysts change in the GTI console: `new`, `read`, `escalated`, `in_progress`, `closed`, `no_action_required`, `duplicate`, `not_relevant`, `tracked_external`. Filtering on status restricts **which alerts are collected at all**. It does not cause an alert to be re-collected when its status later changes — see [Status changes are not re-collected](#status-changes-are-not-re-collected). ### Document inlining and record size **Include Documents** (`refs=true` on the API) attaches the matched document, its labels, and its extracted topics to every alert. That document is the substance of the alert — the actual forum post, paste contents, or credential record — but it is large. Measured against the live API, inlining documents multiplies record size roughly **44x**: about **54 KB** per alert versus about **1.2 KB** without. For a destination billed per gigabyte ingested, such as Microsoft Sentinel, that difference is significant at volume. The setting therefore defaults to **off**. Two ways to enable it without taking the full cost: - Turn on **Include Documents** and set **Truncate** to cap document fields at a fixed number of characters. - Turn on **Include Documents** and narrow **Alert Types** to the categories whose content you actually need. With documents off, each alert still carries its title, summary, type, status, severity, monitor, timestamps, extracted topic and label matches, and the `doc_url` / `labels_url` / `topics_url` links to retrieve the full content on demand. ## How collection works - **Cron-polled and incremental.** Each run requests alerts created since the last alert collected, oldest first, and advances a cursor as it goes. - **Ordered by creation time.** The input sorts and tracks progress on `created_at`. The API's `since` / `until` filters apply to `created_at` regardless of the sort requested, so aligning the cursor with the filtered field is what keeps the walk gap-free. - **Paginated via the `Link` header.** Pages are followed using the token the API returns. The API rejects any request that sends a page token alongside other parameters, so each subsequent page carries the token alone. - **25 alerts per page.** This is the documented maximum. - **Backfill.** With a **Backfill Start Time**, the first run walks forward from that timestamp to the present, then continues incrementally. Without one, collection starts from the time the input first runs. - **Resumable mid-page.** If a run is interrupted partway through pagination, the next run resumes from the same page rather than restarting the window. ### Status changes are not re-collected Each alert is collected **once, when it is created**. If an analyst later moves an alert from `new` to `escalated` to `closed`, that transition is **not** re-emitted to your pipeline — the record you received reflects the alert's state at collection time. This follows from how the API filters: date bounds apply to `created_at`, so a cursor that tried to track updates would progressively hide older alerts instead. If you need triage state downstream, read it from the GTI console or query the API directly for the alerts you care about. ## Sample Record With **Include Documents** off (the default): ```json { "id": "cmje5vmbenj434u3nnvg", "monitor_id": "clb20lirrtn3gnjncs40", "monitor_version": 1, "created_at": "2026-01-16T20:11:42.468Z", "updated_at": "2026-01-20T11:17:36.261Z", "alert_type": "Domain Discovery", "alert_summary": "See alert content for details", "title": "Suspicious domain \"mwise.example.com\" similar to \"example.com\"", "status": "escalated", "severity": "medium", "confidence": 80, "doc_url": "https://www.virustotal.com/api/v3/dtm/docs/domain_discovery/d35713ca-707d-436d-84a5-220e3ae75b61", "labels_url": "https://www.virustotal.com/api/v3/dtm/docs/domain_discovery/d35713ca-707d-436d-84a5-220e3ae75b61/labels", "topics_url": "https://www.virustotal.com/api/v3/dtm/docs/domain_discovery/d35713ca-707d-436d-84a5-220e3ae75b61/topics", "doc_matches": [], "topic_matches": [ { "topic_id": "95eed43c-8f51-49ce-a1d8-f88b5441cec3", "value": "mwise.example.com", "offsets": [6, 18], "term": "example.com" } ], "label_matches": [], "tags": [], "has_analysis": false, "email_sent_at": "", "indicator_attributions": [], "indicator_mscore": 0 } ``` With **Include Documents** on, each record additionally carries `doc` (the matched content, whose shape varies by alert type), `labels`, and `topics`. ## Troubleshooting ### Common Issues 1. **Authentication Errors (401 / 403)** - `401` means the key itself is wrong. Re-copy it from the API Key page, or have the group administrator re-copy the service account key. - `403` means the key is valid but **not entitled to DTM**. Digital Threat Monitoring requires GTI Enterprise or Enterprise Plus; confirm licensing with your GTI account team. 2. **No Records Collected** - Confirm at least one **DTM monitor** exists in the GTI console. Alerts are only generated for configured monitors. - Check whether your **Alert Types**, **Statuses**, **Severities**, or **Minimum Indicator MScore** filters are narrower than intended — each one restricts what is collected. - Without a **Backfill Start Time**, only alerts created after the input first ran are collected. Set one to reach back. 3. **Records Are Much Larger Than Expected** - **Include Documents** is on. Inlined documents are roughly 44x the size of an alert without them. Set **Truncate** to cap document length, narrow **Alert Types**, or turn the setting off. 4. **An Alert's Status Is Stale** - Expected. Alerts are collected once at creation; later triage transitions are not re-emitted. See [Status changes are not re-collected](#status-changes-are-not-re-collected). 5. **Duplicate Records** - Delivery is **at least once**. Records are keyed on the stable alert `id`, so duplicates can be de-duplicated downstream. A record at the exact boundary of a resumed window may be re-sent; the connector suppresses most of these automatically. 6. **Rate Limiting (429)** - The connector backs off and retries automatically. DTM allows 10 concurrent list-alert requests per user and 50,000 API requests per 24 hours. If throttling persists, lower the optional **API Rate Limit**. 7. **Repeated 4xx Responses Stop Collection** - DTM caps requests returning `400` or above at 100 per hour per user. A persistently misconfigured input can exhaust that budget; fix the underlying error and collection resumes in the next hour. ## Related Articles - [Google Threat Intelligence API overview](https://gtidocs.virustotal.com/reference/api-overview) - [List DTM alerts](https://gtidocs.virustotal.com/reference/get-alerts) - [DTM pagination](https://gtidocs.virustotal.com/reference/dtm-pagination) - [DTM limits and quotas](https://gtidocs.virustotal.com/docs/dtm-limits-quotas) - [Digital Threat Monitoring overview](https://gtidocs.virustotal.com/docs/digital-threat-monitoring) - [Mandiant Advantage → GTI API migration guide](https://gtidocs.virustotal.com/docs/mati-api-migration-guide)