SPB Git forge
28commits 1branches 0releases
7.7 MBsize
maindefault branch
10 days agolast push
Python 66.3% TypeScript 22.7% JavaScript 8.6% HTML 1.4% CSS 0.7%
2.4 KB · 42 lines python
Raw Blame History
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