# Jobs Deleted API Endpoint Documentation

Track permanently deleted job postings with a durable sequence-based synchronization feed.

---

## Introduction

The Jobs Deleted endpoint provides a durable feed of job postings that were permanently deleted from the jobdata database. It is designed for downstream systems that maintain a local copy of job data and need to remove listings when they are no longer available in the API.

This endpoint is different from the [Jobs Expired endpoint](/c/jobs-expired-api-endpoint-documentation/). Expiration describes the lifecycle state of a job posting while it remains in the database. The Jobs Deleted records jobs that have been removed permanently and exposes enough identifying information for a client to find and delete the corresponding local record.

The endpoint does not provide a single-job detail route. Use the `job_id` in a deletion record to identify the job in your local system. The job itself is no longer available from `/api/jobs/` after deletion.

## Endpoint Overview

**Endpoint:** `/api/jobsdeleted/`

**Method:** `GET`

**Authentication:** Yes

**Description:** Retrieves a list of all jobs that have been removed form the jobdata API database permanently. The feed is especially useful for search indexes, job boards, data warehouses, analytics pipelines, and other integrations that synchronize job records over time.

## Request

Send requests to the endpoint with the API key in the `Authorization` header.

### Using curl

```bash
curl -G "https://jobdataapi.com/api/jobsdeleted/" \
  -H "Authorization: Api-Key YOUR_API_KEY" \
  --data-urlencode "page_size=1000"
```

### Using Python

```python
import requests

url = "https://jobdataapi.com/api/jobsdeleted/"
headers = {"Authorization": "Api-Key YOUR_API_KEY"}
params = {"page_size": 1000}

response = requests.get(url, headers=headers, params=params, timeout=45)
response.raise_for_status()
data = response.json()

for deletion in data["results"]:
    print(deletion["sequence"], deletion["job_id"])
```

## Access and Pagination

A valid API key enables the full paginator. The default page size is **200** records, and `page_size` accepts values from **1** through **4000**. Standard page-number parameters are also available:

- **page**: Selects a page of results. This requires an API key.
- **page_size**: Sets the number of results per page, from 1 through 4000. This requires an API key.
- **after**: Restricts results to records where `after < sequence`. This requires an API key and must be a non-negative integer.
- **change_id**: Returns only records whose `change_id` exactly equals the supplied value.

Results are ordered by descending `sequence`, so the newest deletion records appear first. `sequence` is an ever-increasing cursor assigned when a deletion is recorded. The `after` parameter is an exclusive lower-bound filter: for example, `after=1200` returns records with sequence values greater than 1200, still ordered from highest sequence to lowest sequence.

The `change_id` comparison is exact. It is useful when a known import, correction, or administrative operation needs to be audited or synchronized separately. It is not a partial-text or case-insensitive search.

For a normal incremental synchronization, store the greatest sequence value successfully processed by your integration. On a later request, send that value as `after` and process the returned records. Advance the stored cursor only after the corresponding local deletions have completed successfully.

### Anonymous Requests

Without an API key, the endpoint permits the default first page only. The anonymous page is limited to 100 records. Requests using `page`, `page_size`, or `after` require an API key with an access subscription and return a permission error without one.

## Response Structure

The endpoint uses the standard paginated response format:

- **count**: The total number of matching deletion records.
- **next**: A URL for the next page, or `null` when there is no next page.
- **previous**: A URL for the previous page, or `null` on the first page.
- **results**: An array of deletion records.

### Deletion Record Fields

Each item in `results` contains the following fields:

- **sequence**: A unique, monotonically increasing integer assigned to the deletion record. Use this value as the synchronization cursor.
- **job_id**: The integer ID of the deleted job in the jobdata API.
- **ext_id**: The external job identifier, when the source supplied one. This value may be `null`.
- **company_id**: The integer ID of the company associated with the deleted job.
- **source_id**: The integer ID of the ATS or source associated with the deleted job.
- **application_url**: The application URL stored on the job at deletion time.
- **published**: The original publication timestamp of the job, or `null` when it was not available.
- **deleted_at**: The timestamp at which the deletion record was created, in ISO 8601 format.
- **change_id**: An optional operation identifier supplied when the deletion was performed. It may be `null` when no identifier was provided.

### Example Response

```json
{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "sequence": 1202,
      "job_id": 987654,
      "ext_id": "ats-4567",
      "company_id": 321,
      "source_id": 14,
      "application_url": "https://example.com/jobs/ats-4567/apply",
      "published": "2026-08-15T09:30:00Z",
      "deleted_at": "2026-08-16T10:45:12.123456Z",
      "change_id": "bad-import-2026-08-16"
    },
    {
      "sequence": 1201,
      "job_id": 987653,
      "ext_id": null,
      "company_id": 321,
      "source_id": 14,
      "application_url": "https://example.com/jobs/ats-4566/apply",
      "published": "2026-08-15T08:15:00Z",
      "deleted_at": "2026-08-16T10:45:12.123456Z",
      "change_id": null
    }
  ]
}
```

## Synchronization Example

The following example keeps a local deletion cursor and removes each matching job from a local store. The cursor is advanced only after the response has been processed successfully.

```python
import requests

API_URL = "https://jobdataapi.com/api/jobsdeleted/"
API_KEY = "YOUR_API_KEY"
last_sequence = 1200

response = requests.get(
    API_URL,
    headers={"Authorization": f"Api-Key {API_KEY}"},
    params={"after": last_sequence, "page_size": 1000},
    timeout=45,
)
response.raise_for_status()
data = response.json()

for deletion in data["results"]:
    local_jobs.delete_by_job_id(deletion["job_id"])

if data["results"]:
    last_sequence = max(
        deletion["sequence"] for deletion in data["results"]
    )
    save_last_sequence(last_sequence)
```

For a large backlog, use the `next` URL from the paginated response until it becomes `null`. Keep the cursor update and local deletion work durable so that a failed request or interrupted process can be retried safely.

## Deletion Sources

Deletion records are created when jobs are permanently removed through our internal job deletion workflow. A deletion record includes a snapshot of the job identifiers and source metadata needed for downstream cleanup. Here the optional `change_id` value can be supplied to group related deletions. For example, a correction run might use `bad-import-2026-08-16` for every affected job. Querying `change_id=bad-import-2026-08-16` then returns exactly the records assigned to that operation.

## Notes and Recommendations

- Replace `YOUR_API_KEY` with an API key from your dashboard.
- Treat `sequence` as an opaque integer cursor. Do not derive it from job IDs or timestamps.
- Store the greatest successfully processed sequence value and make local deletion operations idempotent.
- Use `change_id` for targeted audit or correction workflows, not as a replacement for the sequence cursor.
- Preserve `ext_id`, `company_id`, and `source_id` when useful for reconciling records across systems.
- A deletion record is a notification that the job was removed; it is not a replacement for a full historical job archive.
- Do not assume that `deleted_at` is the same as the original source ATS removal time. It is the time the deletion was recorded in our database.

This endpoint gives you a compact and reliable way to remove stale job records from downstream systems while retaining the source and operation context needed for auditing.
