FirstStage Jobs API
Query jobs from FirstStage boards through one API with ?source=firststage — plus how FirstStage's board pages really behave.
FirstStage is an applicant tracking system with per-tenant boards at
<tenant>.firststage.co. That sentence is close to the limit of what we can tell
you about the company, and this page is going to be short because of it.
What we have is a board, read end to end: one tenant, 107 postings, every field
populated on all 107. What we don't have is the thing the rest of these pages open
with — who buys it, how many employers run on it, how the platform sits in its
market. We could pad this out with plausible sentences about the vendor, and you'd
have no way to tell which ones we'd checked. So: the board behaves as described
below, the rows are queryable with ?source=firststage, and everything else here
is a gap we're naming rather than filling.
How FirstStage boards actually work#
Two calls per posting, not one. The board lists, the posting carries the body:
curl "https://<tenant>.firststage.co/jobs" # the cards
curl "https://<tenant>.firststage.co/jobs/<id>/view" # JSON-LD, full bodyThe board is a Next.js app, and the useful surprise is that it server-renders
every card — so there's no flight-payload parsing to do, no build-id-coupled
format to chase between Next releases. You read the anchors. The detail page
carries a schema.org JobPosting block with the description (5,088 characters on
the posting we measured), datePosted, validThrough and baseSalary.
It's an N+1: a posting per request, so a board costs as many calls as it has jobs. That's the ordinary case in this pool, not a complaint.
It tells you who the employer is#
Worth calling out, because most boards don't. FirstStage's JSON-LD fills
hiringOrganization.sameAs — the employer's actual homepage — and the logo, on
every posting we've seen. A board slug is a string; a homepage is a
company. Most platforms in this pool hand you a token
like northwind and leave you to work out who that is, which is a whole pipeline.
Here the board just says.
What bites you#
The card links are absolute, and the obvious regex finds nothing. Every href
on the board is a fully-qualified https://<tenant>.firststage.co/jobs/<id>/view,
not a relative /jobs/.... Reach for href="/…" — which is the pattern that works
on nearly every other board — and you match zero cards, on a page that returned a
perfectly healthy 200 with all its jobs rendered in it. The board reads as empty
and nothing anywhere says otherwise.
One location field can hold several locations. jobLocation.address is a
plain string, and a multi-location posting comma-joins them:
"London, United Kingdom, Sunnyvale, California USA" is two places. Parse it
as one and you get a city called London and a country called USA.
US addresses drop the comma before the country. "Sunnyvale, California USA" —
so the trailing segment reads as California USA, which is not a country and
doesn't resolve against anything. Between them, those two quirks accounted for
roughly 43% of this source's country fill. Both are fixable once seen: walk the
comma-separated parts and close a location whenever a part is a country or ends
with one.
Or use ours#
Two calls per posting, hrefs in the one form the obvious regex won't match, and a
location field that comma-joins two places and then drops the comma before the
country. None of it announces itself: the board returns a healthy 200 with every
job rendered in it whether you read it correctly or not.
You get the anchors matched in the shape the board actually emits, the N+1 walked,
the description, datePosted, validThrough and baseSalary read off the
JSON-LD, multi-location strings split back into separate places, country segments
closed on the part that is or ends with a country, and
hiringOrganization.sameAs carried through to a real
company rather than a slug you'd have to resolve
yourself.
Query it with ?source=firststage. How many rows that returns is a number that
moves, so read it — and the rest of the live vocabulary — from the sources keys
of /v1/meta, which is the list that's true at the
moment you read it. Quickstart, then pricing.
Every source above normalises onto the same schema, with the hiring company already joined onto each posting.
Get an API key