The official Python SDK for the JobsPipe API - search live job postings and detect website tech stacks.
Project description
JobsPipe Python SDK
The official Python library for the JobsPipe API.
Every job posting, one API. Search millions of live jobs from 30+ sources (LinkedIn, Y Combinator, company career pages, and more), normalized into one clean schema — plus website tech-stack detection.
- Synchronous and asynchronous clients
- Fully typed responses (pydantic models, ships
py.typed) - Automatic retries with
Retry-Aftersupport - Transparent offset pagination (
client.jobs.iter(...)) - A typed exception hierarchy you can branch on
Installation
pip install jobspipe
Requires Python 3.8+.
Authentication
Get an API key from your JobsPipe dashboard (it starts
with jp_live_). Pass it directly or set the JOBSPIPE_API_KEY environment
variable — the client reads it automatically.
export JOBSPIPE_API_KEY="jp_live_..."
Quickstart
from jobspipe import Jobspipe
client = Jobspipe() # reads JOBSPIPE_API_KEY, or Jobspipe(api_key="jp_live_...")
results = client.jobs.search(
description_or=["python", "django"],
job_country_code_or=["US"],
remote=True,
posted_at_max_age_days=7,
limit=25,
include_total_results=True,
)
print(f"{results.metadata.total_results} matches")
for job in results.data:
print(f"{job.job_title} @ {job.company} ({job.country_code}) — {job.url}")
Detect a website's tech stack
scan = client.stack.scan("stripe.com")
print(f"{scan.domain} scanned at {scan.scanned_at} (HTTP {scan.http_status})")
for tech in scan.detected:
print(f" {tech.name:20} {tech.confidence:>3.0f}% {', '.join(tech.categories)}")
Pagination
client.jobs.iter(...) walks every page for you and yields individual jobs.
It stops automatically when there are no more results, or when max_results
is reached.
for job in client.jobs.iter(
description_or=["rust"],
remote=True,
page_size=100,
max_results=500,
):
print(job.job_title, "-", job.company)
Prefer manual control? search() accepts offset/page and the response
exposes metadata.next_cursor (which is None on the last page).
Async
Every method has an async counterpart on AsyncJobspipe:
import asyncio
from jobspipe import AsyncJobspipe
async def main():
async with AsyncJobspipe() as client:
results = await client.jobs.search(remote=True, limit=10)
async for job in client.jobs.iter(description_or=["go"], max_results=50):
print(job.job_title)
asyncio.run(main())
Error handling
All errors derive from jobspipe.JobspipeError. HTTP errors are
APIStatusError subclasses carrying the status code, request id, and parsed body.
from jobspipe import (
Jobspipe,
AuthenticationError,
PaymentRequiredError,
RateLimitError,
APIStatusError,
APIConnectionError,
)
client = Jobspipe()
try:
client.jobs.search(limit=10)
except AuthenticationError:
print("Bad or missing API key")
except PaymentRequiredError:
print("Monthly quota exceeded — upgrade your plan")
except RateLimitError as e:
print(f"Rate limited; retry after {e.retry_after}s")
except APIStatusError as e:
print(f"API error {e.status_code}: {e.message} (request {e.request_id})")
except APIConnectionError:
print("Could not reach the API")
| Exception | When |
|---|---|
BadRequestError |
400 — malformed request / invalid domain |
AuthenticationError |
401 — missing or invalid API key |
PaymentRequiredError |
402 — monthly quota exceeded |
NotFoundError |
404 — resource not found |
RateLimitError |
429 — too many requests (.retry_after) |
InternalServerError |
5xx — server error / gateway timeout |
APITimeoutError |
request timed out |
APIConnectionError |
network failure |
Retries & timeouts
Transient failures (429, 408, 409, 5xx, and network errors) are retried
automatically with exponential backoff, honoring the server's Retry-After
header. Configure per-client:
import httpx
from jobspipe import Jobspipe
client = Jobspipe(
max_retries=4, # default 2
timeout=httpx.Timeout(30.0, connect=5.0), # default 60s
)
Configuration
| Parameter | Default | Env var |
|---|---|---|
api_key |
— | JOBSPIPE_API_KEY |
base_url |
https://api.jobspipe.dev |
JOBSPIPE_BASE_URL |
timeout |
60s (10s connect) | — |
max_retries |
2 | — |
default_headers |
— | — |
http_client |
new httpx.Client |
— |
The response models allow extra fields, so new attributes added by the API are
preserved (accessible via attribute or model_extra) without an SDK upgrade.
Likewise, search() forwards any unknown keyword argument as a filter.
Development
pip install -e ".[dev]"
ruff check .
mypy src
pytest
The test suite mocks HTTP with respx — no
network or API key required. Set JOBSPIPE_API_KEY to additionally run the live
smoke test.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jobspipe-0.1.0.tar.gz.
File metadata
- Download URL: jobspipe-0.1.0.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a561bad31bec5857a0f188d42ca0b9eadee56ea54f0adc8ea0842d717d3449a
|
|
| MD5 |
b1372cf4e2056cefa7878091a7891986
|
|
| BLAKE2b-256 |
848788e8bd8e722a9f5d40c1ca2a6387afda0c662faa495e711eea67a764edd4
|
File details
Details for the file jobspipe-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jobspipe-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa0fab33f6ea6450cae1c57036f6e9055705a48ad837bc1f50b0a79b071316f7
|
|
| MD5 |
d3fc0894aaa14839fceee71dc6763d48
|
|
| BLAKE2b-256 |
d2b13fc7ddc033d5048f6c6d86e95eed24385b67becd389bc13ed04791d04244
|