- criticalWhy does searching an unknown company slug return jobs anyway?
- The paginated search endpoint falls back to an unrelated global result set instead of erroring on an unknown slug. Re-verify the slug through the company endpoint before every run and reject any row whose employerId differs from the board you asked for.
- highWhy did an employer's slug stop matching my stored value?
- SeeMeHired slugs are renamed in place — a live audit found three stale aliases in 145 rows. Store the numeric employerId as the stable key and re-read the current slug from the company endpoint each run, using it only to build display and apply URLs.
- mediumWhy do most jobs come back with isActive false?
- Boards keep historical postings addressable, so inactive rows greatly outnumber live ones — an audit found 123 of 144 proved jobs inactive. Treat isActive=false, closed=true, and isJobInternal=true as structured unavailability and publish only the active remainder.
- lowWhy does a job page not link back to the employer's board?
- Some employers set hideCompanyProfile, and around 15% of job pages omit the opportunities link entirely. The company endpoint keyed on the numeric employerId is the authoritative fallback; never reconstruct the board URL from a third-party company name.
SeeMeHired Jobs API.
Pull every vacancy from a SeeMeHired employer board through an unauthenticated JSON API, keyed on the numeric employer ID so a renamed company slug never splits or merges the wrong employer.
What's in every response.
Data fields, real-world applications, and the companies already running on SeeMeHired.
Data fields
- Full Job Descriptions
- Numeric Employer IDs
- Active & Closed Flags
- Location Matching
- Internal vs Public Jobs
- Company Profile Data
Use cases
- 01UK Job Board Aggregation
- 02Care & Hospitality Hiring Feeds
- 03SMB Recruitment Research
- 04Careers Page Monitoring
Trusted by
- Abicare
- Altogether Care
- Andras Hotels
How to scrape SeeMeHired.
Step-by-step guide to extracting jobs from SeeMeHired-powered career pages—endpoints, authentication, and working code.
from urllib.parse import urlparse
PUBLIC_HOST = "seemehired.com"
def parse_seemehired(url: str) -> dict:
parsed = urlparse(url)
if parsed.netloc.lower() != PUBLIC_HOST:
raise ValueError("not a SeeMeHired URL")
parts = [p for p in parsed.path.strip("/").split("/") if p]
if len(parts) == 2 and parts[0] == "jobs" and parts[1].isdigit():
return {"kind": "job", "job_id": parts[1]}
if len(parts) == 2 and parts[0] == "opportunities":
return {"kind": "board", "slug": parts[1]}
raise ValueError("unrecognised SeeMeHired route")
print(parse_seemehired("https://seemehired.com/jobs/68594"))
# {'kind': 'job', 'job_id': '68594'}import requests
API = "https://api.seemehired.com/public"
def resolve_employer(job_id: str, session: requests.Session) -> dict | None:
job = session.get(f"{API}/jobs/{job_id}", timeout=30)
if job.status_code in (404, 410):
return None # the posting is gone
job.raise_for_status()
record = job.json()
employer_id = record.get("employerId")
if not isinstance(employer_id, int) or employer_id <= 0:
return None
company = session.get(f"{API}/companies/{employer_id}", timeout=30)
company.raise_for_status()
return {
"employer_id": employer_id,
"slug": company.json().get("slug"),
"job_token": record.get("jobToken"),
}
session = requests.Session()
print(resolve_employer("68594", session))def verified_slug(employer_id: int, session: requests.Session) -> str:
resp = session.get(f"{API}/companies/{employer_id}", timeout=30)
resp.raise_for_status()
slug = resp.json().get("slug")
if not slug:
raise RuntimeError(f"employer {employer_id} no longer publishes a slug")
return slug
def listings_url(slug: str, page: int) -> str:
return (
f"{API}/jobs/search/paginated"
f"?companySlug={slug}&locationMatch=exact&limit=500"
f"&page={page}&internalJobs=false"
)
slug = verified_slug(304, session) # Abicare
print(listings_url(slug, 1))def fetch_board(employer_id: int, slug: str, session: requests.Session) -> list[dict]:
collected, page = [], 1
while True:
resp = session.get(listings_url(slug, page), timeout=30)
resp.raise_for_status()
payload = resp.json()
rows = payload.get("jobs") or payload.get("results") or []
total = payload.get("total")
for row in rows:
if row.get("employerId") != employer_id:
raise RuntimeError(
"search returned a foreign employer — this is the unknown-slug "
"fallback, not this board. Abort instead of expiring jobs."
)
collected.append(row)
if not rows or (total is not None and len(collected) >= total):
return collected
page += 1
jobs = fetch_board(304, slug, session)
print(f"{len(jobs)} rows for employer 304")import time
def hydrate(job_id: str, employer_id: int, session: requests.Session) -> dict:
resp = session.get(f"{API}/jobs/{job_id}", timeout=30)
if resp.status_code in (404, 410):
return {"id": job_id, "state": "removed"}
resp.raise_for_status()
record = resp.json()
if record.get("employerId") != employer_id:
raise RuntimeError("detail contradicted the listing employer")
if not record.get("isActive") or record.get("closed") or record.get("isJobInternal"):
return {"id": job_id, "state": "unavailable"}
return {
"id": job_id,
"state": "active",
"title": record.get("title"),
"description_html": record.get("description"),
"listing_url": f"https://seemehired.com/jobs/{job_id}",
"apply_url": f"https://seemehired.com/jobs/{slug}/{job_id}?company={slug}",
}
for row in jobs[:3]:
print(hydrate(str(row["id"]), 304, session)["state"])
time.sleep(0.1)- 1Key the employer on the numeric employerId, never on the mutable slug
- 2Re-verify the slug through the company endpoint before every listings run
- 3Request limit=500 with internalJobs=false and page until count reaches total
- 4Abort the snapshot when any row names a different employer
- 5Separate HTTP 404/410 removal from isActive=false structured unavailability
- 6Keep the numeric employer ID and slug on every emitted row for audit trails
One endpoint. All SeeMeHired jobs. No scraping, no sessions, no maintenance.
Get API accesscurl "https://connect.jobo.world/api/jobs?sources=seemehired" \
-H "X-Api-Key: YOUR_KEY"Try the API.
Test Jobs and Feed endpoints against https://connect.jobo.world with live request/response examples, then copy ready-to-use curl commands.
Access SeeMeHired
job data today.
One API call. Structured data. No scraping infrastructure to build or maintain — start with the $5 free starting balance and scale as you grow.