Integrations · Databases and warehouses

Load job postings data into PostgreSQL

Upsert job posts into a PostgreSQL table with the raw JSON in a jsonb column - queryable with SQL and safe to re-run.

Steps

You need: Python 3.9+, pip install requests "psycopg[binary]" and a jobdata API key.

  1. Copy the fetch helper below and set your API key.
  2. Point the connection string at your database; the script creates the table on first run.
  3. Each job is upserted by its id, so re-runs update rows instead of duplicating them.
  4. Schedule the script daily (cron, a scheduler or your orchestrator).
PostgreSQL · python
import requests

API_KEY = "YOUR_API_KEY"


def fetch_jobs(**params):
    """Yield every job for the given filters, following pagination."""
    url = "https://jobdataapi.com/api/jobs/"
    params = {"page_size": 1000, **params}
    headers = {"Authorization": f"Api-Key {API_KEY}"}
    while url:
        resp = requests.get(url, headers=headers, params=params, timeout=60)
        resp.raise_for_status()
        data = resp.json()
        yield from data["results"]
        url, params = data["next"], None  # "next" already carries the filters


import psycopg
from psycopg.types.json import Jsonb

UPSERT = """
    INSERT INTO jobs (id, title, company, location, published, application_url, data)
    VALUES (%s, %s, %s, %s, %s, %s, %s)
    ON CONFLICT (id) DO UPDATE SET
        title = EXCLUDED.title,
        location = EXCLUDED.location,
        application_url = EXCLUDED.application_url,
        data = EXCLUDED.data
"""

with psycopg.connect("postgresql://user:password@localhost/jobs") as conn:
    conn.execute("""
        CREATE TABLE IF NOT EXISTS jobs (
            id bigint PRIMARY KEY,
            title text,
            company text,
            location text,
            published timestamptz,
            application_url text,
            data jsonb
        )
    """)
    with conn.cursor() as cur:
        for job in fetch_jobs(max_age=1):
            cur.execute(UPSERT, (
                job["id"], job["title"], job["company"]["name"], job["location"],
                job["published"], job["application_url"], Jsonb(job),
            ))

Notes

  • Run it daily with max_age=1 to pick up new job posts; on access lite, drop max_age - the feed covers the past 90 days and upserting by id keeps it free of duplicates.
  • Query nested fields straight from the JSON, e.g. data->'company'->>'website_url', or add columns for the fields you filter on most.
  • Remove closed listings with the expired jobs endpoint (access pro) or the expired field, so your copy never shows stale posts.

Related docs and tutorials

Jobs API Ingestion Guide: Reliable Historical Backfills and Incremental Syncs

A practical guide to high-volume historical backfills and incremental syncs using bounded windows, multi-pass pagination, ID deduplication, and reconciliation.

Date, ID, and Age Slicing Parameters Documentation

Slice smarter, sync faster: precise dataset windows for the /api/jobs/ endpoint

Jobs Expired API Endpoint Documentation

Tracking the lifecycle of job postings.

Ready to load real data?

All endpoints are public for limited testing - run the script without a key to see the structure, then add your key. Flat monthly plans with unlimited usage.

More integrations

All integrations »

Markdown version

Explore jobdata API with AI tools

Ask an AI assistant how to search and build with live job data.