All platforms

JobScore Jobs API

Query jobs from JobScore boards through one API with ?source=jobscore — plus how JobScore's Atom feed and its structured salary really behave.

?source=jobscoresource reference

JobScore is an applicant tracking system for small and mid-sized employers. Boards live on a shared host at careers.jobscore.com/careers/<company>, and every one of them publishes an Atom feed carrying the whole board with descriptions inline. One unauthenticated GET, no token, no detail pass. On the board we tested that was 30 jobs, all 30 with descriptions.

Thirty. Nobody is building an ATS integration for thirty jobs, which is the honest pitch for a platform this size: the work isn't the fetch, it's that this is one of dozens of boards that each need their own quirks learned, and JobScore has two worth learning.

Salary, and why this one is different#

Salary is the weakest field we serve. Across the whole dataset it's populated on 36.0% of postingshas_salary=true throws away roughly two thirds of everything before your other filters even run. That's not a collection failure so much as a publishing one: most employers don't post pay, and most of the platforms that let them don't model it. Where salary does exist, it usually exists as prose, in the body, and getting a number out means mining a sentence and hoping.

JobScore publishes a real one. It extends Atom with a j: namespace, and inside each entry sits a j:publicCompensation block:

Illustrative — the shape of an entry's compensation block
<j:publicCompensation>
  <j:salaryMinimum>95000</j:salaryMinimum>
  <j:salaryMaximum>125000</j:salaryMaximum>
  <j:currencyCode>USD</j:currencyCode>
  <j:interval>year</j:interval>
  <j:formatted>$95,000 - $125,000 / year</j:formatted>
</j:publicCompensation>

Minimum, maximum, currency, interval, and the employer's own formatted string — structured, typed, no regex over a paragraph. That is rare for an ATS at this end of the market and it's the most interesting thing about the platform. Ashby, Rippling and Pinpoint publish structured comp too; a small-business ATS bothering to is unusual.

How JobScore boards actually work#

One GET, no auth, the whole board:

BASH
curl "https://careers.jobscore.com/jobs/<company>/feed.atom"

Note the path: the feed is under /jobs/<company>/, while the human-facing board is /careers/<company> on the same host. <company> is the slug either way, and it's a path segment on a shared host rather than a per-tenant subdomain like most of this pool — which is why JobScore has something almost nobody here does: a native index. careers.jobscore.com/sitemaps/careers.xml.gz lists 504 slugs, live and sanctioned by robots.txt. On most platforms every customer is an isolated subdomain and the board list has to be assembled from nothing. Here you can just ask.

There is no pagination cap, which we probed rather than assumed: one board returned 60 entries in a single document, and every board's Atom count matched its careers page exactly — 60/60, 30/30, 11/11, 5/5. The feed has no paging controls because it doesn't need any.

Per entry you get <title>, <content> with the full body, <updated> as an ISO 8601 timestamp with a zone, and a rel="alternate" link to the posting.

What bites you#

Categories are scheme-keyed, not order-keyed. Location and department both arrive as <category> elements, distinguished only by their scheme attribute:

XML
<category scheme="…#department" term="Clinical"/>
<category scheme="…#location" term="Remote in Joinville, Santa Catarina, Brazil"/>

Boards emit several categories and there is no fixed order, so reading "the first category" or "the second" gets you a department in your location field on some boards and not others. Match the scheme.

An empty feed is a live board, and this one cost us. A JobScore tenant with zero openings serves a valid, empty feed at 200. Only a 404 means the board is gone. Requiring at least one <entry> as proof of life scored the platform at 5% live and discarded real boards that simply weren't hiring that week — a healthy employer between roles is not a dead tenant, and treating it as one deletes it permanently.

The id is buried in a tag URI. Entries identify themselves as tag:jobscore.com,2026-04-22:/dFF1n7ML1lS7CdX9T3vco-. The job id is the trailing path segment, and unlike most of this pool it's globally unique rather than tenant-local, so it doesn't need scoping to dedupe.

Or use ours#

JobScore is one of the few platforms here you could reasonably do by hand: one GET, no auth, no pagination, and a sanctioned sitemap so even the board list is just a download. If that's your whole requirement, take the feed.

?source=jobscore is served, and what it adds is the normalisation and the judgement calls. j:publicCompensation lands as the same salary object with annual_min and annual_max that every other source normalises onto, so JobScore's typed band is directly comparable to a number mined out of prose elsewhere — and salary data is honest about where that comparison strains. Categories are read by their scheme rather than their position. An empty feed is treated as a live board between roles, not a dead tenant, which is the mistake that once scored this platform at 5% live. Ids come off the tag URI, already globally unique.

One caveat that outlives all of this: /v1/metasources is the authority on what you can filter on. source is a csv filter, not an enum, so a miscased ?source=JobScore returns an empty array rather than a 400 — indistinguishable from a board that simply isn't hiring.

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

Get an API key