All platforms

PageUp Jobs API

Query jobs from PageUp boards through one API with ?source=pageup — plus how PageUp's listing endpoint and its #job-details wrapper really behave.

?source=pageupsource reference

PageUp is an enterprise talent management platform with a heavy footprint in higher education and in Australia and New Zealand — universities, health services, state agencies, the kind of employer with a thousand open roles and a procurement process. Boards live at careers.pageuppeople.com/<orgId>/<code>/<lang>/, and there are 8,644 PageUp postings in this dataset — a number that moves hourly, so read it from /v1/meta rather than trusting this sentence.

Try it#

BASH
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "source=pageup" \
  --data-urlencode "time_frame=7d" \
  --data-urlencode "limit=2"
Illustrative — the shape, not a live response
{
  "data": [
    {
      "id": "pageup:533_caw_en_694218",
      "title": "Lecturer, Environmental Science",
      "company": {
        "slug": "kelvin-university",
        "name": "Kelvin University",
        "domain": "kelvin.edu.au",
        "website": "https://kelvin.edu.au",
        "logo": "https://media.licdn.com/dms/image/…",
        "industry": "Higher Education",
        "employee_count": 4200
      },
      "location": {
        "remote": false,
        "countries": ["Australia"],
        "cities": ["Melbourne"],
        "regions": ["Victoria"],
        "raw": ["Bundoora Campus, Melbourne, VIC"]
      },
      "employment_type": ["FULL_TIME"],
      "work_arrangement": null,
      "seniority": null,
      "salary": null,
      "skills": ["teaching", "research"],
      "taxonomies": ["Education"],
      "apply_url": "https://careers.pageuppeople.com/533/caw/en/job/694218",
      "url": "https://careers.pageuppeople.com/533/caw/en/job/694218",
      "source": "pageup",
      "posted_at": "2026-07-08T00:00:00.000Z",
      "expires_at": "2026-08-05T13:59:00.000Z",
      "updated_at": "2026-07-14T05:33:18.000Z"
    }
  ],
  "total": 2,
  "limit": 2,
  "offset": 0
}

salary is null there and it is not an omission: PageUp exposes no structured pay field. expires_at being real, on the other hand, is unusual — most ATS publish no deadline at all.

How PageUp boards actually work#

No JSON API, no JSON-LD, HTML at both levels. The list is the easy half:

BASH
# 1. List — a plain GET, 100 per page, 1-indexed
curl "https://careers.pageuppeople.com/<orgId>/<code>/<lang>/listing/?page=1&page-items=100"
 
# 2. Detail — one per posting; the body only exists here
curl "https://careers.pageuppeople.com/<orgId>/<code>/<lang>/job/<jobId>"

That's genuinely all the list takes. No POST, no token, no handshake, and page-items=100 works — which makes PageUp one of the cheapest listings in this pool to enumerate. The cost is the second call: the listing's <tr class="summary"> is a teaser that looks like a description, so every posting needs its own fetch.

Three things you can't derive#

boardToken is the <orgId>/<code>/<lang> triple, and all three vary:

From https://careers.pageuppeople.com/533/caw/en/listing/
orgId533 — a bare number
codecaw — also seen as cw, eb, ci, and others
langen — or en-us

None of it is derivable from a company's own careers domain. A university links its PageUp board from a page on its own site, and the triple is whatever PageUp assigned it.

The body is in #job-details on most tenants, not all#

This is the structural thing to know about PageUp. The description sits in a <div id="job-details"> on the standard template — but not everywhere. One university's board has no such wrapper at all; the body sits directly in #job-content, and reading only #job-details scores 0 of 10 on that tenant while looking perfectly healthy on every other. With the fallback in place it's 50 of 50 across five tenants.

That's the shape of every PageUp problem: the template is tenant-configurable, so anything you key off has to be the thing that survives the customisation.

What bites you#

page is 1-indexed, and page=0 returns zero rows. Not page one — zero rows. So the off-by-one you'd normally shrug at silently drops the entire first page, and the board reads as smaller than it is with no error anywhere.

page-items caps at 100 silently. Ask for 200 and you get 100, at HTTP 200, with nothing to say you were trimmed.

Exactly 100 looks like a cap and usually isn't

A board returning exactly page-items worth of rows is the classic tell of a silent truncation, and here it's usually just a board with more than 100 jobs. The only way to know is to fetch page 2. Guessing either way is wrong: assume it's a cap and you stop early, assume it isn't and you never check.

<h1> is the site name on the standard template and the job title on custom ones. "Careers at Kelvin University" is not a job. Key off the <h2> inside #job-content and fall back to <h1>, never the reverse.

Labels are tenant-configurable, so key off the CSS class. One tenant writes Job no, another Job No., another translates it. The class names are the stable part of the markup; the text next to them isn't.

<time datetime="…Z"> disagrees with the text beside it. The attribute is Z-suffixed while the adjacent literal string says "Eastern Daylight Time" — the two are up to five hours apart, and there's no way to tell which the tenant meant. We keep it, because the date is what a recency filter uses and that survives the ambiguity, but don't read posted_at on this source as a precise instant.

There's no structured salary at all. Not on the listing, not on the detail. Pay appears in the description prose or not at all, which is why salary is null on PageUp postings far more often than on a platform that publishes a real field. That's the platform, not us.

Or use ours#

PageUp is the case where the fetch really is easy and the parsing really isn't. One GET gets you a hundred job ids. Then the template forks per tenant, the body moves between two wrappers, the <h1> means two different things, the labels are whatever the customer typed, and the timestamp contradicts itself.

You get the description from whichever wrapper the tenant actually used, the title from the element that is a title on both templates, the requisition id read by class rather than by label text, a real expires_at where the board published a closing date, and the company join — a PageUp board tells you 533/caw/en and nothing whatsoever about who that is.

Refresh cadence varies by source, and a detail fetch per posting puts PageUp at the expensive end even though its listing is cheap. See coverage; don't assume uniform latency across sources.

Query it with ?source=pageup. Quickstart · Pricing

Every source above normalises onto the same schema, with the hiring company already joined onto each posting.

Get an API key