spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1"""Greenhouse job board — public endpoint used by every `boards.greenhouse.io/<token>` page:2`GET https://boards-api.greenhouse.io/v1/boards/{token}/jobs?content=false` → {"jobs":[{id, title, absolute_url, location:{name}, updated_at,3first_published, departments?, offices?, requisition_id}]}. Verified 2026-09-12 against the `stripe` board (fixture trimmed to 20 jobs)."""4from __future__ import annotations56import re7from collections.abc import Mapping8from typing import Any910from companyatlas.connectors._ats_base import AtsConnector11from companyatlas.connectors._util import parse_date, text_of12from companyatlas.sdk.connector import ConnectorMeta, register13from companyatlas.sdk.models import ExtractedJob14from companyatlas.taxonomy import FetchMode, Surface151617@register18class GreenhouseConnector(AtsConnector):19 vendor = "greenhouse"20 token_re = re.compile(r"boards-api\.greenhouse\.io/v1/boards/([a-z0-9_-]+)", re.IGNORECASE)21 meta = ConnectorMeta(connector_id="greenhouse-v1", name="Greenhouse job board", version="1", category=Surface.JOBS_BOARD,22 fetch_mode=FetchMode.JSON, supports_discovery=False, supports_incremental=True, default_interval_s=6 * 3600,23 url_pattern=r"boards-api\.greenhouse\.io/v1/boards/", priority=50, pattern_required=True, accept="application/json",24 description="Public Greenhouse Job Board API (jobs list without descriptions)")2526 def parse_jobs(self, data: Any, sensor: Mapping[str, Any]) -> list[ExtractedJob]:27 items = data.get("jobs") if isinstance(data, dict) else data28 out: list[ExtractedJob] = []29 for j in items or []:30 if not isinstance(j, dict) or not j.get("title"):31 continue32 depts = j.get("departments") or []33 offices = j.get("offices") or []34 out.append(ExtractedJob(35 title=str(j["title"]), url=j.get("absolute_url"), external_id=str(j.get("id") or j.get("internal_job_id") or ""),36 department=text_of(depts[0]) if depts else None, location_text=text_of(j.get("location")),37 posted_at=parse_date(j.get("first_published") or j.get("updated_at")),38 raw={"requisition_id": j.get("requisition_id"), "updated_at": j.get("updated_at"), "offices": [text_of(o) for o in offices][:5],39 "language": j.get("language")},40 ))41 return out42