All platforms

HireHive Jobs API.

Pull every open role from small and international employers in a single JSON call, complete with multilingual descriptions, structured pay tiers, and country data, no HTML parsing required.

Get API access
HireHive
Live
20K+jobs indexed monthly
<3haverage discovery time
1hrefresh interval
Companies using HireHive
JLLTeamwork.comFractal AnalyticsAMCS Group
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.

What's in every response.

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

Data fields
  • Full HTML & Plain-Text Descriptions
  • Structured Compensation Tiers
  • Department & Category
  • Employment & Experience Type
  • Language & Locale Codes
  • Country, City & Apply URL
Use cases
  1. 01International Talent Sourcing
  2. 02Multilingual Job Boards
  3. 03SMB Hiring Trend Analysis
  4. 04Pay-Range Benchmarking
  5. 05Job Board Aggregation
Trusted by
JLLTeamwork.comFractal AnalyticsAMCS Group
DIY GUIDE

How to scrape HireHive.

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

RESTbeginnerNo published limit; pace requests ~200ms apart, one at a timeNo auth

Resolve the company subdomain

Each employer runs on its own hirehive.com subdomain; take the company label from the careers URL and pull its full job feed from a single API endpoint.

Step 1: Resolve the company subdomain
# HireHive URL patterns:
# Job board:   https://{company}.hirehive.com
# Jobs API v2: https://{company}.hirehive.com/api/v2/jobs

company = "jungle"
api_url = f"https://{company}.hirehive.com/api/v2/jobs"

Fetch jobs from the v2 endpoint

A single GET to /api/v2/jobs returns every active job with full descriptions, so no per-job detail request is required. Request a large page_size to minimise round trips.

Step 2: Fetch jobs from the v2 endpoint
import requests

company = "jungle"
url = f"https://{company}.hirehive.com/api/v2/jobs"

response = requests.get(url, params={"page_size": 100}, timeout=10)
response.raise_for_status()
data = response.json()

meta = data.get("meta", {})
print(f"Found {meta.get('total_items')} jobs across {meta.get('total_pages')} pages")

Parse each job item

Each item carries structured location and country objects plus both an HTML and a plain-text description. Fall back to a constructed URL when hosted_url is absent so every record keeps an apply link.

Step 3: Parse each job item
for job in data["items"]:
    hosted_url = job.get("hosted_url") or f"https://hirehive.com/jobs/{job['id']}"
    country = (job.get("country") or {}).get("name")
    print({
        "id": job["id"],
        "title": job.get("title"),
        "location": job.get("location"),
        "country": country,
        "category": (job.get("category") or {}).get("name"),
        "employment_type": (job.get("type") or {}).get("name"),
        "description_html": (job.get("description") or {}).get("html", "")[:200],
        "description_text": (job.get("description") or {}).get("text", "")[:200],
        "apply_url": hosted_url,
        "published_date": job.get("published_date"),
    })

Page through the full board

For boards with more than one page, follow meta.has_next_page and increment the page number until it turns false. Pace requests to stay friendly to the API.

Step 4: Page through the full board
import requests
import time

def fetch_all_hirehive_jobs(company: str, page_size: int = 100) -> list:
    base_url = f"https://{company}.hirehive.com/api/v2/jobs"
    all_jobs = []
    page = 1

    while True:
        params = {"page": page, "page_size": page_size}
        response = requests.get(base_url, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()

        all_jobs.extend(data.get("items", []))

        if not data.get("meta", {}).get("has_next_page"):
            break

        page += 1
        time.sleep(0.2)  # ~200ms between requests, one at a time

    return all_jobs

jobs = fetch_all_hirehive_jobs("jungle")
print(f"Total jobs fetched: {len(jobs)}")

Extract structured metadata

Beyond the description, each job exposes department, employment and experience type, language/locale, and an optional compensation_tiers array with min/max pay and currency. Map these into your schema.

Step 5: Extract structured metadata
for job in data["items"]:
    tier = (job.get("compensation_tiers") or [{}])[0]
    record = {
        "external_id": job["id"],
        "title": job.get("title"),
        "department": (job.get("category") or {}).get("name"),
        "employment_type": (job.get("type") or {}).get("type"),      # e.g. "FullTime"
        "experience": (job.get("experience") or {}).get("name"),
        "language": (job.get("language") or {}).get("code"),         # e.g. "es-ES"
        "salary": job.get("salary"),                                 # free-text, often null
        "pay_min": tier.get("min_value"),
        "pay_max": tier.get("max_value"),
        "currency": tier.get("currency_code"),
    }
    print(record)
Common issues
mediumFinding company subdomains

HireHive publishes no public directory of boards. Discover subdomains by following 'hirehive.com' links from company careers pages, job aggregators, and postings, then reuse the subdomain as the company identifier.

mediumHTTP 404 on inactive boards

A subdomain that is not a live HireHive board returns 404. Treat a 404 from /api/v2/jobs as 'company not found' and skip it rather than retrying.

mediumTransient auth and rate-limit responses

Boards can return 401 (auth required), 403 (blocked), or 429 (too many requests). Back off and retry with a delay on 403/429, and keep to a single request at a time.

lowMissing hosted_url on some jobs

A few jobs omit hosted_url. Fall back to constructing a link from the id (https://hirehive.com/jobs/{id}) so every record keeps a working apply URL.

lowLocalized, multi-language content

Titles, descriptions, and category names are returned in the board's own language. Read language.code (e.g. 'es-ES') to detect and route non-English postings before downstream processing.

lowMissing salary and compensation data

The salary field is free-text and often null, and compensation_tiers can be empty. Default these to null and read pay from the first tier's min_value/max_value/currency_code when present.

Best practices
  1. 1Call /api/v2/jobs once per company — it returns full descriptions, so no per-job detail fetch is needed
  2. 2Page with page_size=100 and stop when meta.has_next_page is false
  3. 3Pace requests ~200ms apart and keep concurrency to a single request per board
  4. 4Use description.html for formatted content and description.text for plain text
  5. 5Treat HTTP 404 as an inactive board and skip it instead of retrying
  6. 6Read language.code to detect non-English postings before downstream processing
Or skip the complexity

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

Get API access
cURL
curl "https://connect.jobo.world/api/jobs?sources=hirehive" \
  -H "X-Api-Key: YOUR_KEY"
Ready to integrate

Access HireHive
job data today.

One API call. Structured data. No scraping infrastructure to build or maintain — start with the free tier and scale as you grow.

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