The Feed API has two endpoints designed to be used together:Documentation Index
Fetch the complete documentation index at: https://jobo.world/docs/llms.txt
Use this file to discover all available pages before exploring further.
- Stream active jobs —
POST /api/jobs/feed. Paginated stream of full job objects (active postings only). - Detect expired jobs —
GET /api/jobs/expired. Paginated stream of IDs that have expired in the last 7 days.
Both endpoints are included with a Feed subscription — no per-request credits needed. On pay-as-you-go plans,
/feed charges 0.5 credits per delivered job; /expired is always free so callers can keep their inventory clean.Keeping your system in sync
A typical integration runs an initial backfill, then an incremental sync on a schedule. Useid as your primary key — it’s stable across updates, so syncs are simple upserts.
1. Initial backfill
Page through the entire feed once with cursor pagination. Persistnext_cursor after every successful batch so a crash resumes mid-stream rather than restarting from page 1. Stop when has_more is false.
2. Incremental sync
Run on a schedule (15–60 minutes is a healthy range — more frequent burns credits without much fresh data). Each run:- Read your stored
last_run_started_at. Recordnowasthis_run_started_atbefore the first request. - Call
/feedwithposted_after = last_run_started_at - 15m(a small overlap protects against clock skew and late-arriving postings). - Page through with
cursoruntilhas_moreisfalse. Upsert each job byid. - After the loop succeeds, persist
this_run_started_atas the newlast_run_started_at.
updated_at lets you detect re-published edits — store it and skip writes when it hasn’t changed.
3. Handling deletions
/feed only returns active jobs, so jobs that expire silently disappear. Sweep them with /expired on the same schedule as the incremental sync:
cursor, and mark every returned id as expired in your store.
4. Backoff & rate limits
- On
503, wait the seconds named inRetry-After(currently5) before retrying. The Typesense circuit breaker reopens within ~15 s. - On
400 Invalid cursor, drop the cursor and restart pagination — don’t loop on the same value. - Watch
X-Credits-Balanceto alert before you run dry.
End-to-end examples
These samples implement the full workflow against a small key-valuestore. Replace store with your real database (Postgres upsert, etc.).
Endpoints
Full request/response reference and a live “Try it” playground live on the dedicated pages below.Stream active jobs
POST /api/jobs/feed — cursor-paginated stream of full job objects (active postings only).Detect expired jobs
GET /api/jobs/expired — paginated stream of IDs that have expired in the last 7 days.JobDto schema
Both feed endpoints (and the search endpoints) return job objects in this shape:| Field | Type | Description |
|---|---|---|
id | string (uuid) | Stable Jobo job identifier — use as the primary key when upserting. |
title | string | Original job title as published by the employer. |
normalized_title | string|null | Normalized canonical title (snake_case, e.g. "software_engineer"). |
company | object | Embedded company summary. See Company below. |
description | string | Full job description. HTML is stripped but line breaks are preserved. |
summary | string|null | Short AI-generated summary (2–3 sentences). |
listing_url | string | Canonical URL to view the job on the employer’s careers site. |
apply_url | string | Direct application URL (may equal listing_url). |
locations | object[] | All resolved locations for this posting. See Location. |
compensation | object|null | Normalized compensation range, or null if undisclosed. See Compensation. |
employment_type | string|null | One of "full_time", "part_time", "contract", "internship", "temporary". |
workplace_type | string|null | One of "remote", "hybrid", "onsite". |
experience_level | string|null | One of "entry", "mid", "senior", "lead", "executive". |
source | string | ATS / job board source (e.g. "greenhouse", "lever", "workday"). |
created_at | string (datetime) | UTC timestamp the job was first ingested into Jobo. |
updated_at | string (datetime) | UTC timestamp of the last change to the posting. Watch this for re-syncs. |
date_posted | string|null | UTC date the employer originally posted the job, when known. |
valid_through | string|null | Employer-declared expiry, when available. |
qualifications | object | Structured qualifications. See Qualifications. |
responsibilities | string[] | Bulleted responsibilities extracted from the description. |
benefits | string[] | Bulleted benefits extracted from the description. |
is_work_auth_required | boolean|null | True if applicants must already have work authorization in the job’s country. |
is_h1b_sponsor | boolean|null | True when the hiring company is known to sponsor H-1B visas. |
is_clearance_required | boolean|null | True when a US security clearance is required. |
Company object
Location object
An entry in the
locations[] array. A single posting may cover multiple cities/countries.Compensation object
Qualifications object
Structured qualifications split into must-have and preferred buckets.Each bucket contains:

