# Daily new-jobs check for agents

Run the same search once a day and get only the jobs that are new since the last run, with postedSince and nextSince.

The most common thing an agent does with Trawle is a scheduled check: "tell me about new frontend jobs in Copenhagen every morning." The API is built for this.

## How it works

Every search response includes `nextSince`, the time of that search. Store it. On the next run, send it back as `postedSince`, and you get only jobs that Trawle first saw after your previous run.

```json
{
  "query": { "roles": ["frontend-engineer"], "places": [2618425] },
  "postedSince": "2026-10-30T07:00:00.000Z"
}
```

No overlap and no gaps: a job first seen between two runs shows up in exactly one of them.

## Run once a day

Trawle scans every employer board once a day, starting early in the morning (UTC). `dataDate` in each response says when the data last changed. Running more often than daily just returns empty results; running less often is fine, because `postedSince` catches up on everything since the stored time.

## A complete run

```ts
type State = { since?: string };

async function dailyCheck(state: State) {
  const jobs = [];
  let cursor: string | null = null;
  let nextSince: string | undefined;
  do {
    const response = await fetch("https://trawle.com/v1/jobs/search", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        query: { roles: ["frontend-engineer"], places: [2618425] },
        postedSince: state.since,
        cursor,
        limit: 100,
      }),
    });
    const page = await response.json();
    jobs.push(...page.jobs);
    cursor = page.nextCursor;
    nextSince ??= page.nextSince; // keep the first page's value
  } while (cursor);
  state.since = nextSince; // store only after the run succeeded
  return jobs;
}
```

On the first run there is no stored time. Leave out `postedSince` and you get every matching open job, or use `query.posted: "1d"` (or `"7d"`) to start with a short window.

## Tips

- Store `nextSince` from the first page, and only after the whole run succeeds. If a run fails, the next one picks up from the older time and nothing is lost.
- Keep the query identical between runs. A changed query with an old `postedSince` only returns jobs new since then, not every match for the new query.
- `postedSince` counts from when Trawle first saw the job (`firstSeenAt`), not the employer's "date posted", which is often unreliable.
- Reposts count as new: a job taken down and posted again under a new id has a new `firstSeenAt`. Add `query.reposts: "hide"` to skip them, or check `repostCount`.
- The MCP server offers the same pattern as a `daily_job_search` prompt. See [MCP for agents](https://developers.trawle.com/mcp).
