On this page

The `$expunge` operation permanently deletes a resource and all of its history from the database. Unlike a standard FHIR delete (which creates a "tombstone" record by marking it as deleted), expunge completely removes all traces of the resource.

warning

This operation is **irreversible**. Once a resource is expunged, it cannot be recovered. Use with caution.

## Use Cases
- **Data Cleanup**: Remove test data from development environments
- **Compliance**: Fulfill data deletion requests under regulations like GDPR
- **Tenant Offboarding**: Clean up all data when a tenant leaves the platform
- **Error Correction**: Remove erroneously created resources that shouldn't exist

## Authorization
This operation requires **admin privileges**. You must be a project admin (`Membership.admin = true`).

## Invoke the `$expunge` operation
### Single Resource
```text
[base]/[resourceType]/[id]/$expunge
```
For example, to expunge a single Patient:
```bash
curl -X POST 'https://api.medplum.com/fhir/R4/Patient/example-id/$expunge' \

-H "Content-Type: application/fhir+json" \

-H "Authorization: Bearer MY_ACCESS_TOKEN"
```

### Parameters
| Name | Type | Description | Required |
| --- | --- | --- | --- |
| `everything` | `boolean` | Expunge all resources in the compartment (for Projects only) | No |

### Expunge Everything (Project Compartment)
When expunging a Project or using `everything=true`, the operation deletes all resources belonging to that compartment. This runs as an async job due to the potentially large number of resources involved.
```bash
curl -X POST 'https://api.medplum.com/fhir/R4/Project/project-id/$expunge?everything=true' \

-H "Content-Type: application/fhir+json" \

-H "Authorization: Bearer MY_ACCESS_TOKEN"
```

## Response
### Successful Single Resource Expunge
```json
{

"resourceType": "OperationOutcome",

"issue": [\
\
    {\
\
      "severity": "information",\
\
      "code": "informational",\
\
      "details": {\
\
        "text": "All OK"\
\
      }\
\
    }\
\
  ]

}
```

### Async Job Started (Everything Mode)
When expunging a project or using `everything=true`, the operation returns immediately with a 202 Accepted status and a location header pointing to the async job:
```text
HTTP/1.1 202 Accepted

Content-Location: https://api.medplum.com/fhir/R4/AsyncJob/job-id
```
You can poll the AsyncJob to check the status:
```bash
curl 'https://api.medplum.com/fhir/R4/AsyncJob/job-id' \

-H "Authorization: Bearer MY_ACCESS_TOKEN"
```

### Access Denied
If you don't have admin privileges:
```json
{

"resourceType": "OperationOutcome",

"issue": [\
\
    {\
\
      "severity": "error",\
\
      "code": "forbidden",\
\
      "details": {\
\
        "text": "Forbidden"\
\
      }\
\
    }\
\
  ]

}
```

## Behavior
### Single Resource Expunge
- Deletes the resource and all of its history versions
- Removes associated Binary resources referenced by the resource
- The operation is synchronous and returns immediately

### Everything Mode (Project Expunge)
- Iterates through all resource types in the compartment
- Deletes resources in batches of 10,000
- Also deletes associated Binary resources
- Runs as an async job to handle large datasets

## Related Documentation
- [AsyncJob $cancel](/content/docs/api/fhir/operations/asyncjob-cancel/index.html) - Cancel a running expunge job
- [FHIR Delete](/content/docs/api/fhir/operations/index.html) - Standard FHIR delete (creates tombstone)
- [Use Cases](/content/docs/api/fhir/operations/expunge#use-cases/index.html)
- [Authorization](/content/docs/api/fhir/operations/expunge#authorization/index.html)
- [Invoke the `$expunge` operation](/content/docs/api/fhir/operations/expunge#invoke-the-expunge-operation/index.html)
  - [Single Resource](/content/docs/api/fhir/operations/expunge#single-resource/index.html)
  - [Parameters](/content/docs/api/fhir/operations/expunge#parameters/index.html)
  - [Expunge Everything (Project Compartment)](/content/docs/api/fhir/operations/expunge#expunge-everything-project-compartment/index.html)
- [Response](/content/docs/api/fhir/operations/expunge#response/index.html)
  - [Successful Single Resource Expunge](/content/docs/api/fhir/operations/expunge#successful-single-resource-expunge/index.html)
  - [Async Job Started (Everything Mode)](/content/docs/api/fhir/operations/expunge#async-job-started-everything-mode/index.html)
  - [Access Denied](/content/docs/api/fhir/operations/expunge#access-denied/index.html)
- [Behavior](/content/docs/api/fhir/operations/expunge#behavior/index.html)
  - [Single Resource Expunge](/content/docs/api/fhir/operations/expunge#single-resource-expunge/index.html)
  - [Everything Mode (Project Expunge)](/content/docs/api/fhir/operations/expunge#everything-mode-project-expunge/index.html)
