You can delete records from Grail using the API by leveraging DQL (Dynatrace Query Language), which allows you to specify criteria for selecting records to be deleted.
The record deletion API is primarily designed to help users remove selected records containing sensitive data. Alternatively, you can use
Sensitive Data Center to review and delete data stored in Grail.
Sensitive Data Center utilizes the record deletion API and provides a user-friendly interface on top of it.
With the record deletion API, you can delete records stored in the following tables from both built-in and custom buckets:
logseventsbizeventsspansuser.eventsuser.sessionsuser.replaysapplication.snapshotssecurity.eventsTo delete spans, you need a “trace query entitlement” to be able to execute a fetch spans query. This must be enabled as a capability in your Dynatrace Platform Subscription (DPS).
Record deletion is final and can't be undone.
To access the Swagger API documentation for the record deletion API and to start making API requests using Swagger:
| To do this | Go to Record Delete and select this |
|---|---|
Cancel running process | POST/delete:cancel |
Start new deletion process | POST/delete:execute |
Get status of currently running process | POST/delete:status |
List all deletion tasks and their status | POST/delete:list |
To delete your records, you need to use the /delete:execute endpoint and a DQL query which can contain the following commands and functions.
| Available DQL commands | Available DQL functions |
|---|---|
|
|
The fetch command parameters scanLimitGBytes and samplingRatio are not available in the Record deletion API.
To delete the records, the policy bound to your user group must contain the following permissions:
storage:records:deletestorage:events:readstorage:logs:readstorage:bizevents:readstorage:spans:readstorage:buckets:readThere's no pre-defined policy that grants these permissions—you need to create a custom policy. For instructions, see Manage user permissions with policies.
You can use the following allow statement when creating your policy:
ALLOW storage:records:delete, storage:events:read, storage:logs:read, storage:bizevents:read, storage:spans:read, storage:buckets:read;
If you don't have these permissions, you'll get a 403 error.
When creating an OAuth token or platform token to make API calls from an API client, ensure these permissions are also configured for the token. The user linked to that OAuth token or platform token must have these permissions assigned.
The following examples show curl commands for interacting with the Record Deletion API using a platform token.
Start a new deletion process to delete log records:
curl -X POST "https://<environment>.apps.dynatrace.com/platform/storage/record/v1/delete:execute" \-H "Authorization: Bearer <platformtoken>" \-H "Content-Type: application/json" \-H 'accept: application/json' \-d '{"query": "fetch logs\n | filter contains(content, \"confidential data to be removed\")","timeFrame": {"start": "2025-02-04T00:00:00Z","end": "2025-02-05T00:00:00Z"},"timezone": "UTC"}' \-w "\nHTTP Status Code: %{http_code}\n"> {"taskId":"d2ee1222-2775-4e94-b422-5f948a4349e0"}> HTTP Status Code: 202
Get status of a currently running process:
curl -X 'POST' \'https://<environment>.apps.dynatrace.com/platform/storage/record/v1/delete:status' \-H "Authorization: Bearer <platformtoken>" \-H 'accept: application/json' \-H 'Content-Type: application/json' \-d '{"taskId": "d2ee1222-2775-4e94-b422-5f948a4349e0"}' \-w "\nHTTP Status Code: %{http_code}\n"> {> "status": "finished",> "message": "Records deletion has been successfully completed. 11502351 byte(s) have been rewritten.",> "submittedAt": "2026-06-25T11:32:02Z",> "rewrittenBytes": 11502351> }> HTTP Status Code: 200
List all deletion tasks:
curl -X 'POST' \'https://<environment>.apps.dynatrace.com/platform/storage/record/v1/delete:list' \-H "Authorization: Bearer <platformtoken>" \-H 'accept: application/json' \-d ''> [> {> "taskId": "3b467e4c-94b9-4b58-a91e-c42b125fca7c",> "status": "processing",> "message": "Deletion job is being processed.",> "progress": "0%"> },> {> "taskId": "d2d05c48-f88c-4cd1-992a-965ca5a44c43",> "status": "cancelled",> "message": "Deletion of records cancelled",> "rewrittenBytes": 0> },> {> "taskId": "e06000d8-b5cc-4d11-aa62-e87a223efd4f",> "status": "submitted",> "message": "Deletion job was accepted and is queued for processing."> }> ]> HTTP Status Code: 200
After a deletion task reaches a terminal state:
finished,failed,cancelleddelete:status and delete:list for 24 hours. After that, the task is no longer retrievable from these APIs.To track deletion outcomes beyond 24 hours, use DATA_DELETION_EVENT entries in dt.system.events. These events are created when a deletion task finishes or fails (doesn't apply to cancelled tasks) and are retained much longer. You can query them with:
fetch dt.system.events | filter event.kind == "DATA_DELETION_EVENT"
For details, see DATA\_DELETION\_EVENT.
To avoid excessive deletions on a large volume of records, we introduced the following limitations.
Deleting data using the record deletion API is a hard delete, but it won't reduce the bucket size.
To manage bucket size, go to Settings > Storage management or use the Storage Management API.