# PeopleAdmin Jobs API

> Query jobs from PeopleAdmin boards through one API with ?source=peopleadmin — plus how PeopleAdmin's higher-ed Atom feed really behaves.

Source: https://hyperjobs.io/ats/peopleadmin

PeopleAdmin is the applicant tracking system US higher education runs its hiring
on. Not tech companies, not startups: universities and colleges, with the posting
mix that implies — faculty appointments, lab technicians, groundskeepers,
associate deans, adjuncts. If you're building anything that touches academic
hiring, this is the platform your data lives on, and it's a pool almost nobody
aggregating startup jobs ever looks at.

Every institution gets a tenant at `<tenant>.peopleadmin.com`, and every tenant
publishes an Atom feed with the full posting body inline. One unauthenticated GET,
no auth, no detail pass. On the university board we tested that was 60 postings,
all 60 with descriptions.

## How PeopleAdmin boards actually work

One GET, no auth, the whole board:

```bash
curl "https://<tenant>.peopleadmin.com/postings/search.atom"
```

`<tenant>` is the subdomain — an institution's own short name. Each `<entry>`
carries `<title>`, `<content>` with the complete posting body, `<updated>` as an
ISO 8601 timestamp with a zone, and a link to `/postings/<id>`. The ids are
tenant-local, so they need the tenant folded into any dedup key or two
institutions' posting `5453` will collide.

That's the whole surface. It's a well-behaved feed, and it has three traps.

## What bites you

**`.json` is a trap.** The same path with a `.json` extension looks like it should
work and instead `302`s to `/404`. Only `.atom` is live. Follow the redirect
without checking where you landed and you're parsing an error page.

**`?page=N` is silently ignored, and that looks like a cap.** Pass a page
parameter and you get back a byte-identical document every time. The natural
reading is that the feed caps out around 150 entries and the paging is broken —
so you go hunting for the parameter that unlocks the rest, and there isn't one.

It isn't a cap. We checked it the only way worth checking: walking the board's own
HTML pagination to exhaustion and comparing the id sets.

| Tenant | Distinct ids in the HTML | Entries in the Atom feed |
| --- | --- | --- |
| `chapman` | 149 | 149 |
| `uportland` | 60 | 60 |

The feed returns the complete set in one document, which is why it has no paging
controls. It doesn't need them. (Not proven above ~150 — no tenant we've tested is
bigger — so a very large institution reporting exactly N entries across many HTML
pages is worth re-checking rather than trusting.)

**There is no location. Anywhere.** Not in the feed, not on the detail page. We
checked both. Higher-ed postings state where the job is inside the body prose, in
whatever form the department felt like typing, and the structured field simply
does not exist on this platform. Zero percent is the honest number, and emitting a
guess would be worse than emitting nothing — a wrong location is unfalsifiable
downstream, where a missing one is at least visible.

The obvious repair is the wrong one, too. You cannot default the country to the US
just because PeopleAdmin is a US higher-ed platform: it has **Canadian tenants**.
Vancouver Community College and Capilano University are both real boards here, and
stamping `United States` across them would be confidently, silently wrong on every
posting. Location on this source has to come from the body or from the
institution's own [company profile](/docs/objects/company), not from an assumption
about the vendor's market.

## Or use ours

The feed itself is easy — one GET, no auth, the complete set in a single document
— so for a few institutions you should just read it, minding the `.json` redirect
and not mistaking the ignored `?page=N` for a cap.

`?source=peopleadmin` is served, and what it adds is the pool rather than the
parse. PeopleAdmin publishes no index of its tenants, and academic hiring is not a
board list anyone aggregating startup jobs has assembled — faculty appointments,
lab technicians and adjuncts sit in the same [`Job`](/docs/objects/job) shape as a
[Greenhouse](/ats/greenhouse) engineering role, on [`/ats`](/ats), queryable with
the same filters.

Location is the honest limit and normalisation can't rescue it. The platform has
no location field anywhere, so what's available is the body prose and the
institution's own [company profile](/docs/objects/company) — not a guessed
country, and specifically not the `United States` default that the Canadian
tenants would make silently wrong on every posting. Filter this source
accordingly.

[`/v1/meta`](/docs/api-reference/meta) → `sources` remains the authority on what
you can filter on: `source` is a csv filter, not an enum, so a miscased
`?source=PeopleAdmin` returns an empty array rather than a `400` telling you what
went wrong.
