# User Privacy API v2

> For AI agents: a documentation index is available at [/docs/llms.txt](/docs/llms.txt). Append `.md` to any page URL for markdown, or send `Accept: text/markdown`.

The v2 User Privacy API is currently in development. Endpoints, request bodies, and response shapes may change without notice. For production integrations, use the [v1 API](https://amplitude.com/docs/apis/analytics/user-privacy).

> **Info:** Using the v1 API?
>
> If your integration uses Amplitude's v1 User Privacy API, `/api/2/deletions/users`, on `amplitude.com`, go to the [User Privacy API](https://amplitude.com/docs/apis/analytics/user-privacy) documentation. This page documents v2, hosted at `privacy.amplitude.com`.

## What's new in v2

If you're already integrated with v1, the most important change is how deletion scope is interpreted. v1 defaulted to single-app (project) deletion when scope was unspecified. v2 always deletes across your entire organization. v2 also takes a smaller request body: `amplitudeIds` and `userIds` are renamed and the only parameters it accepts.

| Area | v1 (legacy) | v2 (current) |
| --- | --- | --- |
| Default scope | Single project | Org-wide (all projects) |
| Amplitude IDs | `amplitude_ids` | `amplitudeIds` |
| User IDs | `user_ids` | `userIds` |
| Scope control | Set `delete_from_org: true` for org-wide deletion | Not applicable — all requests delete from org |
| Invalid IDs | Set `ignore_invalid_ids: true` to proceed when an ID isn't found | Not applicable — unknown IDs are always skipped and the rest of the request proceeds |
| Requester | Set `requester` to the email of the person submitting the request | Not applicable — amplitude emails those authorized to submit requests |
| Mapped user IDs | Set `include_mapped_user_ids: true` to return mapped `user_id` values | Not applicable — defaulted to false |
| Endpoint | `POST /api/2/deletions/users` for create, `GET` for status, `DELETE` to remove from staging | `POST /api/user-deletions/org/{orgId}/requests` for create, `GET` for list and status |

> **Note:** delete\_from\_org is v1 only
>
> The `delete_from_org` parameter exists only on the [legacy v1 API](https://amplitude.com/docs/apis/analytics/user-privacy). It is not supported on v2. All deletion requests submitted to `privacy.amplitude.com` delete user data across every project in your organization.

## Endpoints

All v2 routes are scoped to an organization. Replace `{orgId}` with your Amplitude organization ID. Go to [Response bodies](#response-bodies) for the shape of `DeletionResponse` and `DeletionFetchResponse`.

| Operation | Method | Path | Request body | Response body |
| --- | --- | --- | --- | --- |
| List deletion requests | `GET` | `/api/user-deletions/org/{orgId}/requests` | — | `List<DeletionFetchResponse>` |
| Submit deletion request | `POST` | `/api/user-deletions/org/{orgId}/requests` | `DeletionRequest` | `DeletionResponse` |
| Get deletion request | `GET` | `/api/user-deletions/org/{orgId}/requests/{requestId}` | — | `DeletionFetchResponse` |

> **Note:** Canceling requests is not yet supported on v2
>
> v2 does not yet support deleting a request or removing a user from a staging job. If you need to cancel a pending deletion or remove a user before a job runs, continue using the [v1 API](https://amplitude.com/docs/apis/analytics/user-privacy) until this capability ships on v2.

## Regions

The base URL depends on your project's data residency. In all examples on this page, use the default base URL unless your project uses Amplitude's EU data center—in that case use the EU base URL in this table.

| Data residency | Base URL |
| --- | --- |
| Default | `https://privacy.amplitude.com` |
| EU | `https://privacy.eu.amplitude.com` |

Use the host that matches your project's data residency.

## Authentication

Bearer token authentication with your **org-level secret key**.

```http
Authorization: Bearer <org-secret-key>
```

Generate an org-level secret key in Amplitude under **Settings > API Keys > Org-level Secret Keys**. The `orgId` in the request path must match the organization the secret key belongs to. Deletion still applies org-wide across all projects (go to [Org-wide deletion](#org-wide-deletion)). If the **Org-level Secret Keys** page is not yet available for your organization, contact [Amplitude Support](https://gethelp.amplitude.com/hc/en-us) to provision one.

> **Note:** DSAR is separate
>
> [Data Subject Access Requests](https://amplitude.com/docs/apis/analytics/ccpa-dsar) use a different endpoint (`/api/2/dsar/requests`) and also require an **org-level** API key.

## Submit a deletion request

`POST /api/user-deletions/org/{orgId}/requests`

Add users for deletion using a JSON body (`DeletionRequest`). Specify up to 100,000 users at a time. You can use a mix of Amplitude IDs and User IDs. Every request deletes user data across your entire organization.

### Body parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `amplitudeIds` | `int[]` | At least one of `amplitudeIds` or `userIds` | Amplitude IDs to delete. |
| `userIds` | `string[]` | At least one of `amplitudeIds` or `userIds` | User IDs to delete. |

#### Example: Submit a deletion request

```bash
curl --request POST 'https://privacy.amplitude.com/api/user-deletions/org/{orgId}/requests' \
  --header 'Authorization: Bearer <org-secret-key>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "amplitudeIds": [123123, 543221],
    "userIds": ["user_1"]
  }'
```

Amplitude creates one deletion job per project that contains data for any of the specified users. All account admins are emailed with details, including the specific Amplitude IDs scheduled for deletion.

## List deletion requests

`GET /api/user-deletions/org/{orgId}/requests`

Returns all deletion requests for the organization.

```bash
curl --request GET 'https://privacy.amplitude.com/api/user-deletions/org/{orgId}/requests' \
  --header 'Authorization: Bearer <org-secret-key>' \
  --header 'Accept: application/json'
```

## Get a deletion request

`GET /api/user-deletions/org/{orgId}/requests/{requestId}`

Returns a single deletion request by ID.

```bash
curl --request GET 'https://privacy.amplitude.com/api/user-deletions/org/{orgId}/requests/{requestId}' \
  --header 'Authorization: Bearer <org-secret-key>' \
  --header 'Accept: application/json'
```

### Job lifecycle

| State | Meaning |
| --- | --- |
| `STAGING` | Job created but not yet locked in. |
| `SUBMITTED` | Job locked. Runs on the scheduled date. Cannot be modified. |
| `DONE` | Deletion completed across all systems including backups. |

A job moves from `STAGING` to `SUBMITTED` **3 days before** its scheduled run date. After a job becomes `SUBMITTED`, it cannot be canceled.

v2 does not yet expose an API to remove a user from a staging job or cancel a request. Use the [v1 API](https://amplitude.com/docs/apis/analytics/user-privacy) if you need that workflow today.

## Response bodies

Every endpoint returns JSON with camelCase field names. Two shapes cover all three endpoints.

### DeletionResponse

The `POST` endpoint returns a `DeletionResponse`. A `202` carries the ID of the request Amplitude created, and a `400` carries the reason it rejected the request. Exactly one of the two fields is present.

| Field | Type | Description |
| --- | --- | --- |
| `requestId` | `string` | ID of the new deletion request. Pass it to the get endpoint to check progress. Present on `202`. |
| `error` | `string` | Why Amplitude rejected the request. Present on `400`. |

```json
{ "requestId": "20000042" }
```

```json
{ "error": "at least one amplitudeId or userId must be provided" }
```

### DeletionFetchResponse

Both `GET` endpoints return a `DeletionFetchResponse`. The list endpoint returns an array of them, one per request, and the get endpoint returns a single object. A `404` from the get endpoint carries an `error` field instead.

| Field | Type | Description |
| --- | --- | --- |
| `status` | `string` | Status of the request as a whole. Go to [Request status](#request-status) for the values. |
| `requestedAt` | `string` | When the request was submitted, as an ISO 8601 timestamp. |
| `completedAt` | `number` | When the request finished, as a Unix timestamp in seconds. `null` until `status` is `DONE`. |
| `idStatus` | `array` | One entry per ID in the original request. Go to [ID resolution](#id-resolution). |
| `error` | `string` | Why the lookup failed. Present on `404`, in place of the other fields. |

```json
{
  "status": "DONE",
  "requestedAt": "2026-05-22T00:00:00Z",
  "completedAt": 1747872000.0,
  "idStatus": [
    { "userId": "user_1", "ampId": null, "status": "NOT_FOUND" },
    { "userId": null, "ampId": 123456789, "status": "DONE" }
  ]
}
```

#### Request status

| Value | Meaning |
| --- | --- |
| `STAGING` | Request accepted and stored. No work has started. |
| `IN_PROGRESS` | Amplitude is resolving the submitted IDs to the users they belong to. |
| `RESOLVED` | Every ID has been resolved. Deletion jobs haven't been created yet. |
| `SUBMITTED` | Deletion jobs created and locked. They run on their scheduled dates. |
| `DONE` | Deletion completed across all systems including backups. |

`IN_PROGRESS` and `RESOLVED` are transient. A request passes through both on its way from `STAGING` to `SUBMITTED`, usually within minutes.

#### ID resolution

Each entry in `idStatus` reports one ID from the original request. `userId` and `ampId` echo what you submitted, so exactly one of them is set and the other is `null`.

| Field | Type | Description |
| --- | --- | --- |
| `userId` | `string` | The User ID you submitted, or `null` if you submitted an Amplitude ID. |
| `ampId` | `number` | The Amplitude ID you submitted, or `null` if you submitted a User ID. |
| `status` | `string` | What happened to this ID. |

| Status | Meaning |
| --- | --- |
| `STAGING` | Stored, not yet resolved. |
| `RESOLVED` | Matched to a user in your organization. |
| `SUBMITTED` | Attached to a deletion job. |
| `NOT_FOUND` | No user in your organization matches this ID. The rest of the request still proceeds. |
| `DONE` | Data for this user is deleted. |

A `NOT_FOUND` entry is the only way to tell that an ID matched nothing. The request as a whole still reports `DONE`, even if every ID in it was unknown.

## Org-wide deletion

All v2 deletion requests are org-wide. When you submit a request, Amplitude fans the deletion out to every project in the organization that contains data for the listed users.

- One deletion job is created for each project that has matching data.
- All account admins receive an email with the full list of Amplitude IDs scheduled for deletion across the org.

There is no project-scoped deletion mode on v2. If you need to delete from a single project only, use the [legacy v1 API](https://amplitude.com/docs/apis/analytics/user-privacy) without setting `delete_from_org`.

If you previously used v1 without setting `delete_from_org`, your historical deletion requests may have only deleted from a single project. Re-submit those users through v2 to ensure org-wide deletion.

## Service-level commitments and timing

| Commitment | Value |
| --- | --- |
| Maximum deletion completion time | 30 days from request |
| Job revocable until | 3 days before scheduled run date (v1 only until v2 supports cancellation) |

When you make a deletion request, Amplitude [emails all account admins](https://help.amplitude.com/hc/en-us/articles/360031965572-Manage-user-privacy-notifications-in-Amplitude) with the deletion details.

## Important behaviors

### Deletion doesn't stop future tracking

The User Privacy API removes existing data. It does **not** prevent Amplitude from accepting new events for the deleted user. If your SDK continues to send events for them, those events are ingested as a brand-new user. Amplitude has no memory of the deleted identity to re-link against.

To stop future tracking, use the `setOptOut()` method on the Amplitude SDK you're using.

### Warehouse / CDC reingestion

If you ingest data into Amplitude from a data warehouse through Change Data Capture (CDC) or other warehouse-native ingestion methods, deletion in Amplitude does not propagate back to the source. On the next sync, the deleted data may be reingested.

**To ensure complete deletion, delete the data in your warehouse source as well, then re-run the User Privacy API request.** This applies to:

- Snowflake / BigQuery / Databricks / Redshift CDC sources
- Mirror Sync
- Any other warehouse-native ingestion path

### Future event identity

After a deletion, if new events arrive for the same `userId`, they are treated as a new user with a fresh Amplitude ID. There is no automatic re-stitching.

### Statsig data

This User Privacy API only deletes data from the Amplitude platform. To delete data from the Statsig platform, use the [Statsig User Data Deletion Requests API](https://docs.statsig.com/compliance/user_data_deletion_requests).

## Migrating from v1

If you have an existing v1 integration, see the [v1 documentation](https://amplitude.com/docs/apis/analytics/user-privacy) for the legacy endpoint reference. Here's what to change when moving to v2:

### 1. Update your endpoint

```diff
- POST https://amplitude.com/api/2/deletions/users
+ POST https://privacy.amplitude.com/api/user-deletions/org/{orgId}/requests
```

Use the list and get-by-ID `GET` routes above instead of v1's date-range query. v2 does not yet support `DELETE` to remove users from staging — keep using v1 for that workflow if needed.

### 2. Update authentication

v2 uses Bearer authentication with an org-level secret key instead of v1's project API key + secret key.

```diff
- Authorization: Basic <base64(api_key:secret_key)>
+ Authorization: Bearer <org-secret-key>
```

Generate an org-level secret key under **Settings → API Keys → Org-level Secret Keys**.

### 3. Batch your requests

v2 accepts up to 100,000 IDs per request. Batch IDs in each request to delete users efficiently.

### 4. Remove unused parameters

`delete_from_org`, `requester`, `ignore_invalid_ids`, and `include_mapped_user_ids` are v1-only. On v2, all requests delete org-wide by default and invalid ids are ignored by default - you don't need to (and can't) set these flags.

```diff
  {
-   "user_ids": ["user_1"],
-   "requester": "privacy@yourcompany.com",
-   "delete_from_org": true
+   "userIds": ["user_1"]
  }
```

If you were using v1 **without** `delete_from_org`, your requests only deleted from a single project. Migrating to v2 automatically upgrades those requests to org-wide deletion.

### 5. Use request status visibility

v2 exposes `GET` endpoints to list deletion requests and fetch a single request by `requestId`, including lifecycle state (`staging` / `submitted` / `done`).

## Status codes

| Code | Message | Body |
| --- | --- | --- |
| 200 | Success | `DeletionFetchResponse`, or an array of them from the list endpoint |
| 202 | Accepted | `DeletionResponse` with the new `requestId` |
| 400 | Bad Request | `DeletionResponse` with an `error` |
| 401 | Unauthorized | Empty |
| 404 | Not Found | `DeletionFetchResponse` with an `error` |
| 500 | Internal Server Error | Empty |
