# Dynatrace

> Connect the Dynatrace Environment API with a read-scoped access token, send problem notifications to the workspace webhook, and let Smartscape feed the service map.

_How-to · Updated 2026-10-17 · Describes release 0.1.164_

## Overview {#overview}

Dynatrace is three integrations in one connection. The read side: the **Incident** agent reads Davis problems, Smartscape entities, metrics, logs, events and SLOs through the Environment API v2 (alerting, metrics and logs are three of the categories that agent needs), the **SecOps** agent reads its logs, the **FinOps** agent its metrics, and the estate x-ray and the insights chat use it too. Alerting: a problem notification posts each Davis problem to this workspace as one alert, see [Alerts in](#alerts-in). Topology: the hourly service-map sync reads Smartscape's service call relationships, see [Service map](#service-map).

A built-in skill, `dynatrace-problem`, walks the agent through an incident a Dynatrace problem opened: it starts from Davis's own evidence and root-cause entity and checks them, instead of re-deriving the answer.

## Setup {#setup}

### Before you start {#before-you-start}

- The `datasources.manage` permission; the built-in owner and operator roles carry it.
- A classic Dynatrace access token (`dt0c01.…`) with read scopes, `problems.read` at least ([Installation](#installation)).

### Installation {#installation}

In Dynatrace open **Access tokens → Generate new token**, name it `aiops-reader` and select read scopes only: `problems.read` (required; the connection check calls it), `entities.read`, `metrics.read`, `logs.read`, `events.read` and `slo.read`, with `settings.read` optional. Do not add a `.write` or ingest scope. The connector sends a classic access token (`dt0c01.…`) as `Authorization: Api-Token`; a platform token (`dt0s16.…`) cannot carry the environment-API scopes and does not work here.

### Configuration {#configuration}

1. Open **Settings · Data in → Data sources** and select **Connect datasource**.
2. Under **Type**, choose **Dynatrace**. Enter a **Connection name**; the connected list shows it, and per-connection agent tools are named after it.
3. Fill the fields; the TLS-skip field sits under **Advanced connection settings**:

| Field (portal label) | API key | Value |
|---|---|---|
| Environment URL (SaaS: https://\<environment-id\>.live.dynatrace.com; Managed/ActiveGate: https://\<domain\>/e/\<environment-id\>) | `url` | The environment root, without `/api/v2` |
| Access token (problems.read, entities.read, metrics.read, logs.read, events.read, slo.read, settings.read) | `api_key` | The classic access token; stored write-only |
| Skip TLS verify for a self-signed cert (optional — type: true) | `insecure` | `true` only for a self-signed ActiveGate certificate |

4. Optionally, open **Optional · describe this environment** and say in **What should AIOps know about it?** what this system is and what matters.
5. Under **Use this connection for**, choose **Investigate only** and select **Connect and verify**.

The same connection through the API (`POST /api/aiops/{tenant_id}/datasources`, requires `datasources.manage`; the token goes in `secret_values`):

```json
{
  "type_key": "dynatrace",
  "name": "dynatrace",
  "description": "Production environment; services are tagged service:<name> to match the estate inventory.",
  "config": {
    "url": "https://abc12345.live.dynatrace.com"
  },
  "secret_values": {
    "api_key": "<access token>"
  },
  "role": "read",
  "enabled": true
}
```

### Validation {#validation}

**Connect and verify**, and **Test** on the row later, sends a GET to `/api/v2/problems?pageSize=1` with the token as `Authorization: Api-Token`. **You should see** a dialog titled `<connection name> is connected` with **Connected — verified from the control plane**, and later in the row's **Last test** `ok · HTTP 200 /api/v2/problems?pageSize=1 — {"totalCount": …`. A `401` means the token is wrong; a `403` means it lacks `problems.read`. The check proves the token and that one scope; the other scopes show up on the agent's first metric, entity or log read.

### If something fails {#if-something-fails}

The dialog shows **Needs a fix**, what to fix and the check's own detail; the row is saved either way. Select **Edit**, correct the field the detail names and save again, or select **Retry** once a cause outside the form (network, vendor-side permission) is fixed. Every verdict this connector produces, and what to do about it, is in [Troubleshooting](#troubleshooting) below.

## Data collected {#data-collected}

### Tools the agent gets {#tools}

- `<name>_request` — the HTTP tool against the environment URL with `Authorization: Api-Token`: `method`, `path`, `query`, `body`, `content_type`. The skill uses `GET /api/v2/problems/<problemId>` with `fields=evidenceDetails,impactAnalysis`, `GET /api/v2/entities/<entityId>` and `GET /api/v2/entities` with `entitySelector` and `fields=+fromRelationships.calls,+toRelationships.calls`, `GET /api/v2/metrics/query` with `metricSelector`, `entitySelector`, `from` and `resolution`, `GET /api/v2/logs/search`, `GET /api/v2/events`, `GET /api/v2/slo` and `GET /api/v2/settings/objects`.

There is no native Dynatrace tool. Responses are capped at 20,000 characters per call.

### Read surface {#read-surface}

Every read of the Environment API is a `GET`, so `GET` and `HEAD` run freely and every `POST`, `PUT` and `DELETE` — problem comments and close, metric, event or log ingest, settings writes — is refused in an investigation, never offered for approval: `Investigation connections are read-only. This operation was not executed; prepare an incident change using a write connection and obtain approval.` The Grail DQL endpoint, `POST /platform/storage/query/v1/query:execute`, is a read in substance but takes a platform token, not this access token, so it is refused too. The full rule table is under **The read/write gate in detail** in [Connections and remediation access](/help/read-and-write-roles.md#read-role-vs-write-role).

### Alerts in {#alerts-in}

A Dynatrace problem is already Davis's correlated incident, so it arrives as one alert keyed on the problem's `PID`, never one alert per impacted entity. In Dynatrace add a **Problem notification** of type **Custom integration** with the webhook URL `https://<your-host>/webhook/dynatrace/<workspace-slug>`, the token under **Additional HTTP headers** as `Authorization: Bearer <webhook-token>` marked secret, and this payload; keep `{ImpactedEntities}` and `{ProblemDetailsJSONv2}` without quotes, Dynatrace renders them as JSON:

```json
{
  "ProblemID": "{ProblemID}",
  "PID": "{PID}",
  "State": "{State}",
  "ProblemTitle": "{ProblemTitle}",
  "ProblemSeverity": "{ProblemSeverity}",
  "ProblemImpact": "{ProblemImpact}",
  "ImpactedEntities": {ImpactedEntities},
  "ImpactedEntity": "{ImpactedEntity}",
  "Tags": "{Tags}",
  "ProblemURL": "{ProblemURL}",
  "ProblemDetailsText": "{ProblemDetailsText}",
  "ProblemDetailsJSONv2": {ProblemDetailsJSONv2}
}
```

How the adapter reads it:

- `service` is a `service:` tag on the impacted entity, else the impacted `SERVICE` entity's name, else the `APPLICATION`, else the first impacted entity (a host, for an infrastructure problem). Tag your services `service:<name>` with the names in your estate inventory so a Dynatrace problem on checkout joins the alerts already open for checkout; other `key:value` tags become labels too.
- `ProblemSeverity` maps `AVAILABILITY` and `ERROR` to `critical`, `PERFORMANCE`, `RESOURCE_CONTENTION` and `CUSTOM_ALERT` to `warning`, `MONITORING_UNAVAILABLE` and `INFO` to `info`; anything else is `warning`.
- `State` `RESOLVED` or `CLOSED` resolves the alert, matched to the open one by `PID`.
- The alert carries `dynatrace_problem_id` (the id `GET /api/v2/problems/{problemId}` takes), `dynatrace_display_id` (the `P-<n>` a person sees), `dynatrace_impact`, `dynatrace_entity_type`, `impacted_entities` and, when Davis named one, `dynatrace_root_cause`; the annotations carry the title, `problem_url` and the first 2,000 characters of `ProblemDetailsText`.

Dynatrace's **Send test notification** opens one real incident, titled *Dynatrace problem notification test run* on `MyService1`; resolve it by hand. **Alert intake & tokens** also has a **Send a test alert** card for the `dynatrace` source. [Alerts from your observability platform](/help/external-observability.md) covers the newer environments where a Workflow replaces the classic notification. Field by field, with the response counters and error strings: [webhook reference](/help/webhook-reference.md#dynatrace).

### Service map {#service-map}

Once a Dynatrace connection is enabled, the hourly trace sync reads Smartscape's `SERVICE` entities with `GET /api/v2/entities?entitySelector=type("SERVICE")&fields=+fromRelationships.calls` over the last hour, following `nextPageKey` for up to 50 pages, and records each `calls` relationship as a caller → callee edge with origin `traced`. Smartscape carries no call count, so each relationship counts as one call; a workspace that raises the minimum call count above one drops them. Traced edges show on the map and widen the blast radius; they fold incidents only where the workspace opts traced edges in (`aiops_topology_fold_origins`).

## Troubleshooting {#troubleshooting}

| What you see | Cause | What to do |
|---|---|---|
| `failed · HTTP 401 /api/v2/problems?pageSize=1` | The token is wrong, revoked, or a platform token. | Generate a classic access token with the read scopes and replace it on **Edit**. |
| `failed · HTTP 403 /api/v2/problems?pageSize=1` | The token lacks `problems.read`. | Add the scope, or generate a new token with it. |
| `failed · HTTP 404 /api/v2/problems?pageSize=1` | The URL already ends in `/api/v2`, so the check hit `/api/v2/api/v2/problems`. | Enter the environment root only. |
| **Test** is green, but metric, entity or log reads answer `HTTP 403` | The token has `problems.read` but not the scope that read needs. | Add `metrics.read`, `entities.read`, `logs.read`, `events.read` or `slo.read`. |
| A `POST` to `/api/v2/problems/<id>/close`, an ingest endpoint or the Grail query endpoint answers `Investigation connections are read-only.` | The write gate; Grail needs a platform token in any case. | Expected. |
| The notification test answers `401 invalid webhook credentials` | Wrong token, wrong workspace slug or a disabled workspace; the endpoint never says which. | Copy the exact URL and token from **Alert intake & tokens**. |
| A problem opens an incident with the wrong service | No `service:` tag; the impacted entity's own name was used. | Tag the entity `service:<name>`, or map Dynatrace's name with `label_map`. |
| An incident never resolves although the problem closed | The notification is not sent for the closing state, or the payload lost `PID`. | Keep `PID` and `State` in the payload and enable notifications on close. |
| The service map shows no Dynatrace edges | The connection is disabled, write-role, or the sync has not run yet. | Enable a read connection and wait for the hourly sync. |

The generic verdict strings are explained in [Test a connection and read the failure](/help/manage-connections.md#troubleshooting); alert-intake symptoms are in [Alert sources: troubleshooting](/help/setup-alert-sources.md#troubleshooting). Every connection status word is in the [status and error reference](/help/status-and-error-reference.md#connection-statuses).

## Next steps {#next-steps}

- Select **Discover this connection** in the success dialog to find the services and dependencies behind it: [Launch a scan](/help/estate-harvest-and-xray.md#launch-a-scan).
- Send Dynatrace problems in through the workspace webhook: [Alerts in](#alerts-in).
- See which call edges Smartscape adds to the service map: [Service map](#service-map).
- See what else each agent needs in [Choose your connection](/help/choose-your-connection.md#agent-needs).
