# First request carries the filters and batch size.
curl -X POST "https://connect.jobo.world/api/jobs/feed" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sources": ["greenhouse"], "batch_size": 1000}'
# Continuation requests carry ONLY the cursor.
curl -X POST "https://connect.jobo.world/api/jobs/feed" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"cursor": "eyJ2IjoxLCJ..."}'from jobo_enterprise import JoboClient
with JoboClient(api_key="YOUR_API_KEY") as client:
# iter_jobs walks the cursor for you.
for job in client.feed.iter_jobs(sources=["greenhouse"], batch_size=1000):
save_to_database(job)
const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locations: [{country: '<string>', region: '<string>', city: '<string>'}],
sources: ['<string>'],
work_models: [],
employment_types: [],
experience_levels: [],
languages: ['<string>'],
posted_after: '2023-11-07T05:31:56Z',
include_reactivated: false,
description_format: 'markdown',
updated_after: '2023-11-07T05:31:56Z',
stable_scan: true,
cursor: '<string>',
batch_size: 1000
})
};
fetch('https://connect.jobo.world/api/jobs/feed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://connect.jobo.world/api/jobs/feed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'locations' => [
[
'country' => '<string>',
'region' => '<string>',
'city' => '<string>'
]
],
'sources' => [
'<string>'
],
'work_models' => [
],
'employment_types' => [
],
'experience_levels' => [
],
'languages' => [
'<string>'
],
'posted_after' => '2023-11-07T05:31:56Z',
'include_reactivated' => false,
'description_format' => 'markdown',
'updated_after' => '2023-11-07T05:31:56Z',
'stable_scan' => true,
'cursor' => '<string>',
'batch_size' => 1000
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://connect.jobo.world/api/jobs/feed"
payload := strings.NewReader("{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://connect.jobo.world/api/jobs/feed")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://connect.jobo.world/api/jobs/feed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}"
response = http.request(request)
puts response.read_body{
"jobs": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"title": "<string>",
"normalized_title": "<string>",
"company": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"website": "<string>",
"logo_url": "<string>",
"summary": "<string>",
"industries": [
"<string>"
],
"categories": [
"<string>"
],
"linkedin_url": "<string>",
"crunchbase_url": "<string>",
"details_url": "<string>"
},
"description": "<string>",
"language": "en",
"summary": "<string>",
"listing_url": "<string>",
"apply_url": "<string>",
"locations": [
{
"location": "<string>",
"city": "<string>",
"region": "<string>",
"country": "<string>",
"latitude": 123,
"longitude": 123
}
],
"compensation": {
"min": 123,
"max": 123,
"currency": "<string>",
"period": "hourly"
},
"employment_type": "Full-time",
"workplace_type": "Remote",
"experience_level": "Intern",
"source": "greenhouse",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"date_posted": "2023-11-07T05:31:56Z",
"valid_through": "2023-11-07T05:31:56Z",
"qualifications": {
"must_have": {
"education": [
"<string>"
],
"certifications": [
"<string>"
],
"skills": [
{
"name": "<string>",
"type": "hard"
}
]
},
"preferred": {
"education": [
"<string>"
],
"certifications": [
"<string>"
],
"skills": [
{
"name": "<string>",
"type": "hard"
}
]
}
},
"responsibilities": [
"<string>"
],
"benefits": [
"<string>"
],
"is_work_auth_required": true,
"is_h1b_sponsor": true,
"is_clearance_required": true,
"external_id": "000123"
}
],
"next_cursor": "<string>",
"has_more": true,
"estimated_total": 123
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}Stream the job feed
Export active jobs in batches of up to 1,000. Omit cursor on the first
request, then pass only the returned next_cursor — the cursor embeds the
initial filters and batch size, and values sent alongside a cursor are
ignored. Persist the cursor so an interrupted scan can resume, and
paginate serially (one in-flight request per cursor).
New scans default to stable_scan: true: pages follow immutable creation
time, so mid-scan updates or deletions cannot shift records across page
boundaries. Set stable_scan: false explicitly for the legacy
update-recency ordering. Use updated_after for incremental additions
and edits after the backfill.
Retry only 503 (honoring Retry-After) and 429, with bounded
backoff. A 400 for a malformed cursor, or a 409 with code
feed_cursor_restart_required, means discard the cursor and restart
the scan with stable_scan: true. Configure clients with a response
timeout of at least 120 seconds.
Feed bills like Search: delivered jobs use your plan’s included jobs first, then the pay-as-you-go rate; without a plan, the pay-as-you-go rate applies. An Unlimited plan drops per-job charges on Feed, managed Feed, Export, and Outbound unlimited; Search stays pay as you go.
# First request carries the filters and batch size.
curl -X POST "https://connect.jobo.world/api/jobs/feed" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sources": ["greenhouse"], "batch_size": 1000}'
# Continuation requests carry ONLY the cursor.
curl -X POST "https://connect.jobo.world/api/jobs/feed" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"cursor": "eyJ2IjoxLCJ..."}'from jobo_enterprise import JoboClient
with JoboClient(api_key="YOUR_API_KEY") as client:
# iter_jobs walks the cursor for you.
for job in client.feed.iter_jobs(sources=["greenhouse"], batch_size=1000):
save_to_database(job)
const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locations: [{country: '<string>', region: '<string>', city: '<string>'}],
sources: ['<string>'],
work_models: [],
employment_types: [],
experience_levels: [],
languages: ['<string>'],
posted_after: '2023-11-07T05:31:56Z',
include_reactivated: false,
description_format: 'markdown',
updated_after: '2023-11-07T05:31:56Z',
stable_scan: true,
cursor: '<string>',
batch_size: 1000
})
};
fetch('https://connect.jobo.world/api/jobs/feed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://connect.jobo.world/api/jobs/feed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'locations' => [
[
'country' => '<string>',
'region' => '<string>',
'city' => '<string>'
]
],
'sources' => [
'<string>'
],
'work_models' => [
],
'employment_types' => [
],
'experience_levels' => [
],
'languages' => [
'<string>'
],
'posted_after' => '2023-11-07T05:31:56Z',
'include_reactivated' => false,
'description_format' => 'markdown',
'updated_after' => '2023-11-07T05:31:56Z',
'stable_scan' => true,
'cursor' => '<string>',
'batch_size' => 1000
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-Api-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://connect.jobo.world/api/jobs/feed"
payload := strings.NewReader("{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Api-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://connect.jobo.world/api/jobs/feed")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://connect.jobo.world/api/jobs/feed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"locations\": [\n {\n \"country\": \"<string>\",\n \"region\": \"<string>\",\n \"city\": \"<string>\"\n }\n ],\n \"sources\": [\n \"<string>\"\n ],\n \"work_models\": [],\n \"employment_types\": [],\n \"experience_levels\": [],\n \"languages\": [\n \"<string>\"\n ],\n \"posted_after\": \"2023-11-07T05:31:56Z\",\n \"include_reactivated\": false,\n \"description_format\": \"markdown\",\n \"updated_after\": \"2023-11-07T05:31:56Z\",\n \"stable_scan\": true,\n \"cursor\": \"<string>\",\n \"batch_size\": 1000\n}"
response = http.request(request)
puts response.read_body{
"jobs": [
{
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"title": "<string>",
"normalized_title": "<string>",
"company": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"website": "<string>",
"logo_url": "<string>",
"summary": "<string>",
"industries": [
"<string>"
],
"categories": [
"<string>"
],
"linkedin_url": "<string>",
"crunchbase_url": "<string>",
"details_url": "<string>"
},
"description": "<string>",
"language": "en",
"summary": "<string>",
"listing_url": "<string>",
"apply_url": "<string>",
"locations": [
{
"location": "<string>",
"city": "<string>",
"region": "<string>",
"country": "<string>",
"latitude": 123,
"longitude": 123
}
],
"compensation": {
"min": 123,
"max": 123,
"currency": "<string>",
"period": "hourly"
},
"employment_type": "Full-time",
"workplace_type": "Remote",
"experience_level": "Intern",
"source": "greenhouse",
"created_at": "2023-11-07T05:31:56Z",
"updated_at": "2023-11-07T05:31:56Z",
"date_posted": "2023-11-07T05:31:56Z",
"valid_through": "2023-11-07T05:31:56Z",
"qualifications": {
"must_have": {
"education": [
"<string>"
],
"certifications": [
"<string>"
],
"skills": [
{
"name": "<string>",
"type": "hard"
}
]
},
"preferred": {
"education": [
"<string>"
],
"certifications": [
"<string>"
],
"skills": [
{
"name": "<string>",
"type": "hard"
}
]
}
},
"responsibilities": [
"<string>"
],
"benefits": [
"<string>"
],
"is_work_auth_required": true,
"is_h1b_sponsor": true,
"is_clearance_required": true,
"external_id": "000123"
}
],
"next_cursor": "<string>",
"has_more": true,
"estimated_total": 123
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}{
"type": "<string>",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"api_version": "2026-08-31"
}Authorizations
API key provided by Jobo
Body
Cursor-paginated export request. The cursor preserves the filters and batch size from the first request; start a new scan to change them.
Show child attributes
Show child attributes
Filter by work model: remote, hybrid, onsite. null = all jobs
remote, hybrid, onsite Filter by employment type. null = all jobs
full-time, part-time, contract, internship, freelance, temporary Filter by experience level. null = all jobs
intern, entry, mid, senior, lead, executive Filter by description language, as ISO 639-1 codes (en, de, fr). Language names and locales (English, en-US) are mapped to their code. null = all jobs.
Return jobs whose employer posting time or first-indexed time is on
or after this UTC timestamp. Use updated_after when edits matter.
Also return jobs that expired and were reactivated (rediscovered
and re-indexed) on or after posted_after. A reactivated job keeps
its original posting and creation dates, so posted_after alone
never re-delivers it.
Only changes the posted_after filter: it has no effect without
posted_after, and an updated_after sync does not need it —
reactivation re-indexes the job, so updated_after already returns
it. When both posted_after and updated_after are set, a job
must match both.
Format of each job's description. markdown (default) returns it
as stored. html renders it to HTML on the fly: raw HTML in the
source is escaped and only http(s), mailto and relative URLs
are kept. Read from every request, including cursor continuations.
markdown, html Return jobs created, updated or re-indexed on or after this UTC
timestamp. Includes jobs that expired and were reactivated in the
window (reactivation re-indexes the job), so syncs that use
updated_after don't need include_reactivated.
Page by immutable creation time rather than update recency (default). Stable scans cannot skip or duplicate records when jobs are updated or deleted mid-scan. Set false explicitly for the legacy update-recency ordering.
Opaque cursor from next_cursor. Omit on the first request.
1 <= x <= 1000Response
Batch of jobs with cursor for next page

