GetHired Jobs API.

GetHired powers hourly and small-business hiring on easyapply.co. Each employer board publishes a complete RSS feed, and every job page carries canonical JobPosting JSON-LD — no key required.

Get API access

What's in every response.

Data fields, real-world applications, and the companies already running on GetHired.

Data fields

  • Full Job Descriptions
  • JobPosting JSON-LD
  • Complete Per-Tenant Feed
  • Location Categories
  • Published Dates
  • Direct Apply URLs

Use cases

  1. 01Hourly Job Aggregation
  2. 02Small Business Hiring Trackers
  3. 03Local Job Board Syndication
  4. 04Careers Page Monitoring

Trusted by

  • Rosedale Green
  • Langenstein Uptown
  • Langenstein River Ridge
DIY GUIDE

How to scrape GetHired.

Step-by-step guide to extracting jobs from GetHired-powered career pages—endpoints, authentication, and working code.

API type
Hybrid
Difficulty
intermediate
Rate limit
No published limit; ~250ms between requests, max 3 concurrent detail fetches
Authentication
No auth

Resolve the tenant board

GetHired boards are third-level subdomains of easyapply.co. The apex host serves job pages and the vendor gateway, so www, app, api, support and easyapply itself are never tenants. The board root is the subdomain with no path.

Step 1: Resolve the tenant board
from urllib.parse import urlparse

RESERVED = {"api", "app", "easyapply", "support", "www"}

def parse_board(url: str) -> str | None:
    parsed = urlparse(url)
    if parsed.scheme != "https":
        return None
    labels = parsed.netloc.lower().split(".")
    if len(labels) != 3 or labels[1] != "easyapply" or labels[2] != "co":
        return None

    tenant = labels[0]
    if tenant in RESERVED or not 0 < len(tenant) <= 63:
        return None
    return tenant

def parse_job_id(url: str) -> str | None:
    """Jobs appear as /a/{uuid} or /job/{slug} on either host."""
    segments = [s for s in urlparse(url).path.split("/") if s]
    if len(segments) != 2 or segments[0] not in ("a", "job"):
        return None
    return segments[1]

print(parse_board("https://0758kentonhousinginc.easyapply.co"))

Read the tenant RSS feed

Appending /rss to the board root returns the complete inventory in one document — there is no pagination. The channel title is the employer name, and each item carries the title, a description summary, a category holding the location and a publish date.

Step 2: Read the tenant RSS feed
import requests
from xml.etree import ElementTree

def fetch_feed(session, tenant: str) -> list[dict]:
    feed_url = f"https://{tenant}.easyapply.co/rss"
    resp = session.get(feed_url,
                       headers={"Accept": "application/rss+xml"}, timeout=30)
    resp.raise_for_status()

    root = ElementTree.fromstring(resp.content)
    if root.tag.lower() != "rss":
        raise RuntimeError("GetHired response was not an RSS document")
    channel = root.find("channel")
    if channel is None:
        raise RuntimeError("GetHired feed contained no channel")

    company = (channel.findtext("title") or "").strip()
    rows, seen = [], set()
    for item in channel.findall("item"):
        link = (item.findtext("link") or item.findtext("guid") or "").strip()
        job_id = parse_job_id(link)
        if not job_id or job_id in seen:
            continue
        seen.add(job_id)
        rows.append({
            "id": job_id,
            "title": (item.findtext("title") or "").strip(),
            "summary": (item.findtext("description") or "").strip(),
            "location": (item.findtext("category") or "").strip() or None,
            "posted_at": item.findtext("pubDate"),
            "company": company,
            "url": link.split("?")[0],
        })
    return rows

session = requests.Session()
listings = fetch_feed(session, "0758kentonhousinginc")
print(f"{len(listings)} open jobs")

Read JobPosting JSON-LD from each job page

The feed description is a summary. The job page is the canonical record and carries one JobPosting block with the full HTML description, employment type, dates and address. Send the tenant board as the Referer.

Step 3: Read JobPosting JSON-LD from each job page
import json
import time
from bs4 import BeautifulSoup

def find_job_posting(html: str) -> dict | None:
    soup = BeautifulSoup(html, "html.parser")
    for tag in soup.find_all("script", type="application/ld+json"):
        try:
            data = json.loads(tag.string or "")
        except (json.JSONDecodeError, TypeError):
            continue
        for node in (data if isinstance(data, list) else [data]):
            if isinstance(node, dict) and node.get("@type") == "JobPosting":
                return node
    return None

def fetch_detail(session, listing: dict, tenant: str) -> dict | None:
    resp = session.get(
        listing["url"],
        headers={"Accept": "text/html",
                 "Referer": f"https://{tenant}.easyapply.co"},
        timeout=30)
    if resp.status_code in (404, 410):
        return None  # job removed
    resp.raise_for_status()

    posting = find_job_posting(resp.text)
    if not posting:
        return None

    address = ((posting.get("jobLocation") or {}).get("address")) or {}
    return {
        "id": listing["id"],
        "title": posting.get("title") or listing["title"],
        "description_html": posting.get("description"),
        "employment_type": posting.get("employmentType"),
        "posted_at": posting.get("datePosted") or listing.get("posted_at"),
        "closes_at": posting.get("validThrough"),
        "company": (posting.get("hiringOrganization") or {}).get("name")
                   or listing.get("company"),
        "city": address.get("addressLocality"),
        "state": address.get("addressRegion"),
        "url": listing["url"],
    }

for listing in listings[:3]:
    print(fetch_detail(session, listing, "0758kentonhousinginc"))
    time.sleep(0.25)

Attribute a tenantless job link

Syndicated GetHired links usually point at the apex host, easyapply.co/a/{uuid}, which names no employer. The job page links back to the owning board through the company logo and default link anchors, so read the tenant from those and require exactly one match.

Step 4: Attribute a tenantless job link
def resolve_tenant(session, job_url: str) -> str | None:
    resp = session.get(job_url, headers={"Accept": "text/html"}, timeout=30)
    if not resp.ok or not find_job_posting(resp.text):
        return None

    soup = BeautifulSoup(resp.text, "html.parser")
    tenants = set()
    for anchor in soup.select("a.vega-default-link[href], a.jobpage_company_logo[href]"):
        tenant = parse_board(anchor["href"])
        if tenant:
            tenants.add(tenant)

    # Ambiguous attribution is worse than none — require exactly one board.
    return tenants.pop() if len(tenants) == 1 else None

print(resolve_tenant(
    session, "https://easyapply.co/a/414e3fef-dd31-4ec6-b192-04175b7f1fa7"))
Common issues
highFeed links point at easyapply.co, not the tenant subdomain
Items in a tenant's own RSS feed link to the apex host, so a naive host check treats every job as belonging to no board. Take the employer from the feed you requested, and only fall back to page-level attribution for links that arrived from outside.
mediumJob IDs come in two different shapes
GetHired publishes both /a/{uuid} and /job/{slug} routes for the same platform, and both appear in feeds and inbound links. Accept either as the external identifier and normalise by stripping the query string, or the same job is stored twice under different keys.
mediumA tenantless link cannot be attributed
Apex-host job URLs carry no employer. Fetch the page and read the board links in the company logo and default link anchors, requiring exactly one distinct tenant. If two boards appear, leave the job unattributed rather than guessing.
mediumDescriptions are truncated
The RSS description is a teaser, not the posting body. Fetch the job page and read the JobPosting JSON-LD description; storing the feed text leaves every record with a few sentences and no requirements or benefits.
Best practices
  1. 1Use the tenant RSS feed as the inventory and the job page as the record
  2. 2Exclude www, app, api, support and easyapply when deriving a tenant
  3. 3Normalise both /a/{uuid} and /job/{slug} shapes to one external identifier
  4. 4Send the tenant board as the Referer on every job-page request
  5. 5Require exactly one board link before attributing an apex-host job
  6. 6Throttle to ~250ms between requests with at most three concurrent detail fetches
Or skip the complexity

One endpoint. All GetHired jobs. No scraping, no sessions, no maintenance.

Get API access
cURL
curl "https://connect.jobo.world/api/jobs?sources=gethired" \
  -H "X-Api-Key: YOUR_KEY"
Developer tools

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.

Ready to integrate

Access GetHired
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.

99.9%API uptime
<200msAvg response
50M+Jobs processed