# Freshness and reposts

What firstSeenAt, lastSeenAt, openSince, repostCount and closedAt mean, and how Trawle detects closures and reposts.

Trawle reads every employer's board once a day. Comparing one day with the next tells it which jobs are new, which are still open and which have closed. That history is in five fields on every job.

| Field         | Meaning                                                                                                             |
| ------------- | ------------------------------------------------------------------------------------------------------------------- |
| `firstSeenAt` | First time Trawle saw the job under this id. `postedSince` and `posted` filter on this.                             |
| `lastSeenAt`  | Last daily scan that saw it open on the employer's site. For open jobs, that's the latest scan.                     |
| `postedAt`    | The employer's own "date posted", when their system has one. Often unreliable: some systems reset it on every edit. |
| `openSince`   | First time any posting of this job was seen, reposts included. Days open count from here.                           |
| `repostCount` | Earlier postings of the same job under other ids, plus times it closed and reopened. `0` means original.            |
| `closedAt`    | When it disappeared from the employer's site; `null` while open.                                                    |

## Closures

When a job is gone from the employer's board, Trawle marks it closed (`closedAt`) and drops it from search within a day. `GET /v1/jobs/{id}` still returns it, so links you stored keep working. If a board can't be read on a given day (the site is down, say), its jobs are left as they were rather than closed.

## Reposts

Some employers take a job down and post it again under a new id, so it looks fresh. Trawle links the new posting to the old one (same company, title and location) and counts it in `repostCount`. `openSince` carries over, so a job reposted every month still shows how long it has really been open.

```json
{
  "id": "4419023",
  "title": "Senior Frontend Engineer",
  "company": { "slug": "lumen-labs", "name": "Lumen Labs", "domain": "lumenlabs.example" },
  "role": { "slug": "frontend-engineer", "name": "Frontend Engineer" },
  "family": { "slug": "software-engineering", "name": "Software Engineering" },
  "locations": [{ "id": 2618425, "name": "Copenhagen", "country": "DK" }],
  "workplace": "hybrid",
  "remoteScope": null,
  "seniority": "senior",
  "employmentType": "full_time",
  "salary": null,
  "firstSeenAt": "2026-10-30T06:12:00.000Z",
  "lastSeenAt": "2026-10-31T06:12:00.000Z",
  "postedAt": "2026-10-29T00:00:00.000Z",
  "openSince": "2026-09-14T06:10:00.000Z",
  "repostCount": 1,
  "closedAt": null,
  "applyUrl": "https://job-boards.greenhouse.io/lumenlabs/jobs/7712001",
  "url": "https://trawle.com/jobs/4419023"
}
```

This posting is two days old (`firstSeenAt`), but the job has been open since September 14 (`openSince`) and was posted once before.

To skip reposts in a search, use `query.reposts: "hide"`; to find only them, `"only"`.

## History

Trawle's own history starts at `historyStart` in [`GET /v1/stats`](https://developers.trawle.com/api/get-stats). For jobs that were already open then, `openSince` is the first day Trawle saw them, and `postedAt` is the best hint of their real age.
