spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1"""SmartRecruiters postings — public endpoint behind `careers.smartrecruiters.com/<Company>`:2`GET https://api.smartrecruiters.com/v1/companies/{token}/postings?limit=100&offset=N` → {offset, limit, totalFound, content:[{id, name,3uuid, refNumber, releasedDate, location:{city, region, country(iso2 lower), remote, hybrid, fullLocation}, department:{label}, function:{label},4typeOfEmployment:{label}, experienceLevel:{label}}]}. Paginated by offset (bounded). Verified 2026-09-12 against `smartrecruiters`."""5from __future__ import annotations67import re8from collections.abc import Mapping9from typing import Any1011from companyatlas.connectors._ats_base import AtsConnector12from companyatlas.connectors._util import country_code, load_json, merged_result, parse_date, text_of13from companyatlas.fetch import Fetcher, FetchResult14from companyatlas.sdk.connector import ConnectorContext, ConnectorMeta, register15from companyatlas.sdk.models import ExtractedJob16from companyatlas.taxonomy import FetchMode, Surface1718PAGE_SIZE = 10019MAX_PAGES = 10202122@register23class SmartRecruitersConnector(AtsConnector):24 vendor = "smartrecruiters"25 token_re = re.compile(r"api\.smartrecruiters\.com/v1/companies/([a-z0-9_-]+)/postings", re.IGNORECASE)26 meta = ConnectorMeta(connector_id="smartrecruiters-v1", name="SmartRecruiters postings", version="1", category=Surface.JOBS_BOARD,27 fetch_mode=FetchMode.JSON, default_interval_s=6 * 3600, url_pattern=r"api\.smartrecruiters\.com/v1/companies/",28 priority=50, pattern_required=True, accept="application/json", description="Public SmartRecruiters posting API with offset pagination")2930 async def fetch(self, ctx: ConnectorContext, sensor: Mapping[str, Any], fetcher: Fetcher) -> FetchResult:31 base = str(sensor["url"]).split("&offset=")[0]32 first = await fetcher.get(base, etag=sensor.get("etag"), last_modified=sensor.get("last_modified"), accept="application/json")33 data = load_json(first)34 content = list(data.get("content") or []) if isinstance(data, dict) else []35 total = int(data.get("totalFound") or len(content)) if isinstance(data, dict) else len(content)36 pages = 137 offset = len(content)38 while offset < total and pages < MAX_PAGES and content:39 page = await fetcher.get(f"{base}&offset={offset}", accept="application/json")40 more = load_json(page).get("content") or []41 if not more:42 break43 content.extend(more)44 offset += len(more)45 pages += 146 if pages == 1:47 return first48 return merged_result(first, {"totalFound": total, "content": content}, pages=pages)4950 def parse_jobs(self, data: Any, sensor: Mapping[str, Any]) -> list[ExtractedJob]:51 token = self.token(sensor) or ""52 out: list[ExtractedJob] = []53 for j in (data.get("content") if isinstance(data, dict) else []) or []:54 if not isinstance(j, dict) or not j.get("name"):55 continue56 loc = j.get("location") or {}57 jid = str(j.get("id") or j.get("uuid") or "")58 url = f"https://jobs.smartrecruiters.com/{token}/{jid}" if token and jid else None59 remote = True if loc.get("remote") else (False if loc.get("hybrid") is not None or loc.get("city") else None)60 out.append(ExtractedJob(61 title=str(j["name"]).strip(), url=url, external_id=jid, department=text_of(j.get("department")),62 location_text=text_of(loc.get("fullLocation")) or ", ".join(x for x in (loc.get("city"), loc.get("region"), loc.get("country")) if x) or None,63 city=text_of(loc.get("city")), region=text_of(loc.get("region")), country=country_code(loc.get("country")), remote=remote,64 employment_type=text_of(j.get("typeOfEmployment")), seniority=None, posted_at=parse_date(j.get("releasedDate")),65 raw={"refNumber": j.get("refNumber"), "function": text_of(j.get("function")), "experienceLevel": text_of(j.get("experienceLevel"))},66 ))67 return out68