> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reducto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Deleting Jobs & Uploads

> Remove job artifacts and uploaded files before the end of the automatic retention window.

Reducto lets you delete job artifacts and uploaded files on demand instead of waiting for the end of the automatic retention window.

<Note>
  Organizations on Growth and Enterprise tiers already benefit from Reducto's [Zero Data Retention (ZDR) policy](/security/policies), which typically purges all API processing artifacts within 24 hours. These endpoints are for cases where you need to delete artifacts before the 24-hour period.
</Note>

## What gets deleted

`DELETE /job/{job_id}` deletes the **API-layer artifacts** that Reducto stores in live systems when processing a job:

| Artifact type      | Examples                                   |
| ------------------ | ------------------------------------------ |
| Job output         | Parsed JSON, extracted data, split results |
| Intermediate files | Converted images, page renders             |

Uploaded files are managed separately. To remove a file you uploaded via `POST /upload`, use `DELETE /upload/{file_id}`.

When cleanup finishes, Reducto tombstones the job record. Tombstoning marks the record as deleted so Reducto no longer serves it through job retrieval endpoints; residual copies may remain briefly in backups or object-store versions until they are removed through ordinary backup rotation.

**What is not affected:**

* **Studio data.** Jobs created through Studio pipelines are managed separately. These endpoints only delete artifacts stored by the Reducto API.
* **Your source documents.** If you provided a URL to an externally hosted file, that file is untouched.
* **Completed downstream results.** If another job already consumed this job's output (e.g. chained extract after parse), the downstream job's own artifacts remain until you delete them separately.

***

## Delete a job

`DELETE /job/{job_id}` is asynchronous. It validates your request, marks the job as pending deletion, enqueues a background cleanup task, and returns `202 Accepted`. Artifact cleanup runs in the background.

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests

  api_key = os.environ["REDUCTO_API_KEY"]
  base_url = "https://platform.reducto.ai"

  response = requests.delete(
      f"{base_url}/job/{job_id}",
      headers={"Authorization": f"Bearer {api_key}"},
  )
  print(response.status_code)  # 202
  print(response.json())
  # {"job_id": "abc123"}
  ```

  ```javascript Node.js theme={null}
  const apiKey = process.env.REDUCTO_API_KEY;
  const baseUrl = "https://platform.reducto.ai";

  const response = await fetch(`${baseUrl}/job/${jobId}`, {
    method: "DELETE",
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  console.log(response.status);  // 202
  console.log(await response.json());
  // { job_id: "abc123" }
  ```

  ```bash cURL theme={null}
  curl -X DELETE "https://platform.reducto.ai/job/{job_id}" \
    -H "Authorization: Bearer $REDUCTO_API_KEY" \
    -w "\nHTTP status: %{http_code}\n"
  # HTTP status: 202
  ```
</CodeGroup>

### HTTP status codes

Job deletion is asynchronous, so the status codes reflect the lifecycle of the deletion process.

| Code                   | Meaning                              | When                                                                                                                                |
| ---------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| **202 Accepted**       | Deletion request accepted            | Returned by `DELETE /job/{job_id}`. Cleanup is running in the background.                                                           |
| **409 Conflict**       | Deletion in progress                 | Returned by `GET /job/{job_id}` while background cleanup is still running.                                                          |
| **410 Gone**           | Job deleted                          | Returned by `GET /job/{job_id}` after cleanup finishes and the job is tombstoned.                                                   |
| **404 Not Found**      | Job does not exist                   | The job ID is invalid or belongs to a different organization.                                                                       |
| **400 Bad Request**    | Job not in a terminal state          | The job is still pending, in progress, or completing. Only completed or failed jobs can be deleted.                                 |
| **422 Not applicable** | Deletion not available for your tier | On-demand deletion is only available to Growth and Enterprise organizations. The response body carries error code `NOT_APPLICABLE`. |

### Deleting persisted artifacts

If you used `persist_results: true` when creating the job, persisted result artifacts are kept by default even after deletion according to your account settings or agreement with Reducto. Pass `include_persisted=true` to also delete those long-retention artifacts:

<CodeGroup>
  ```python Python theme={null}
  response = requests.delete(
      f"{base_url}/job/{job_id}",
      headers={"Authorization": f"Bearer {api_key}"},
      params={"include_persisted": True},
  )
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    `${baseUrl}/job/${jobId}?include_persisted=true`,
    {
      method: "DELETE",
      headers: { Authorization: `Bearer ${apiKey}` },
    }
  );
  ```

  ```bash cURL theme={null}
  curl -X DELETE "https://platform.reducto.ai/job/{job_id}?include_persisted=true" \
    -H "Authorization: Bearer $REDUCTO_API_KEY"
  ```
</CodeGroup>

### Response

| Field    | Type     | Description                     |
| -------- | -------- | ------------------------------- |
| `job_id` | `string` | The ID of the job being deleted |

Store the deletion response with your own request logs if you need evidence that Reducto accepted the deletion request.

### Failure recovery

If the background cleanup task fails, the deletion marker is rolled back automatically. The job becomes retrievable again via `GET /job/{job_id}` and you can retry the `DELETE` request.

***

## Delete an uploaded file

`DELETE /upload/{file_id}` removes the file you uploaded via `POST /upload`. This operation is synchronous and returns immediately. Pass the full `reducto://` file ID returned by `POST /upload`.

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests

  api_key = os.environ["REDUCTO_API_KEY"]
  base_url = "https://platform.reducto.ai"

  response = requests.delete(
      f"{base_url}/upload/{file_id}",
      headers={"Authorization": f"Bearer {api_key}"},
  )
  print(response.json())
  # {"file_id": "reducto://abc-123-def"}
  ```

  ```javascript Node.js theme={null}
  const apiKey = process.env.REDUCTO_API_KEY;
  const baseUrl = "https://platform.reducto.ai";

  const response = await fetch(`${baseUrl}/upload/${fileId}`, {
    method: "DELETE",
    headers: { Authorization: `Bearer ${apiKey}` },
  });
  console.log(await response.json());
  // { file_id: "reducto://abc-123-def" }
  ```

  ```bash cURL theme={null}
  curl -X DELETE "https://platform.reducto.ai/upload/{file_id}" \
    -H "Authorization: Bearer $REDUCTO_API_KEY"
  ```
</CodeGroup>

### Response

| Field     | Type     | Description                         |
| --------- | -------- | ----------------------------------- |
| `file_id` | `string` | The normalized `reducto://` file ID |

<Note>
  Jobs that already processed this file are not affected. Delete each job separately if needed.
</Note>

***

## Relationship to data retention

These deletion endpoints complement, not replace, Reducto's automatic data retention policies. For the full scope of Reducto's data handling obligations, please refer to Reducto's Data Processing Agreement (DPA).

| Tier                   | Automatic retention                                                                        | Manual deletion                              |
| ---------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------- |
| Growth and Enterprise  | ZDR: all API processing artifacts typically purged within 24 hours                         | Job deletion via `DELETE /job`               |
| With `persist_results` | Results stored for the period specified in your account settings or as agreed with Reducto | Pass `include_persisted=true` to also delete |

For full details on data retention and security policies, see [Data policies & compliance](/security/policies).

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="409: Deletion in progress">
    The job's artifacts are being cleaned up in the background. Wait and retry your `GET /job/{job_id}` request. Once cleanup finishes, the status changes to `410 Gone`.
  </Accordion>

  <Accordion title="410: Job has been deleted">
    The job was deleted from live systems (either manually via this endpoint or by automatic retention). The job record is tombstoned and is no longer retrievable through the API.
  </Accordion>

  <Accordion title="400: Job not in a terminal state">
    Only completed or failed jobs can be deleted. If the job is still processing, wait for it to finish or cancel it first via `POST /cancel/{job_id}`.
  </Accordion>

  <Accordion title="Can I delete Studio jobs?">
    No. Jobs created through Studio pipelines are managed separately. These endpoints only delete artifacts stored by the Reducto API.
  </Accordion>

  <Accordion title="Can I recover a deleted job?">
    No. Deleted jobs are not recoverable through the API. Back up results separately before deleting them in Reducto's database if you need them later.
  </Accordion>

  <Accordion title="What happens if deletion fails?">
    The deletion marker is rolled back automatically. The job becomes retrievable again and you can retry the `DELETE` request.
  </Accordion>
</AccordionGroup>
