# Same body as the first request of POST /api/jobs/feed, without cursor.
curl -X POST "https://connect.jobo.world/api/jobs/feed/preview" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"job_subcategories": {"include": ["Nursing"]}, "company_is_agency": false}'import requests
url = "https://connect.jobo.world/api/jobs/feed/preview"
payload = {
"locations": [{ "country": "United States" }],
"job_subcategories": { "include": ["Nursing"] },
"company_sizes": { "include": ["201-500", "501-1000", "1001-5000", "5001-10000", "10001+"] },
"company_is_agency": False
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locations: [{country: 'United States'}],
job_subcategories: {include: ['Nursing']},
company_sizes: {include: ['201-500', '501-1000', '1001-5000', '5001-10000', '10001+']},
company_is_agency: false
})
};
fetch('https://connect.jobo.world/api/jobs/feed/preview', 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/preview",
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' => 'United States'
]
],
'job_subcategories' => [
'include' => [
'Nursing'
]
],
'company_sizes' => [
'include' => [
'201-500',
'501-1000',
'1001-5000',
'5001-10000',
'10001+'
]
],
'company_is_agency' => false
]),
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/preview"
payload := strings.NewReader("{\n \"locations\": [\n {\n \"country\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\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/preview")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"locations\": [\n {\n \"country\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://connect.jobo.world/api/jobs/feed/preview")
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\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\n}"
response = http.request(request)
puts response.read_body{
"estimated_total": 123,
"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",
"occupation": {
"id": "esco:8d3e8aaa-791b-4c75-a465-f3f827028f50",
"name": "Registered Nurse",
"category": "Healthcare",
"subcategory": "Nursing",
"isco_code": "2221",
"onet_soc_codes": [
"29-1141.00"
]
}
}
],
"warnings": [
{
"code": "companies_unmatched",
"field": "companies.include",
"message": "<string>"
}
]
}{
"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"
}Preview the job feed
Try a POST /api/jobs/feed request before you start a scan: the
preview returns how many jobs the feed would deliver and the first
five. It takes the same body as the feed’s first request and runs the
same first page — the same filters, validation, companies
resolution and warnings — so a request that previews cleanly
streams the same jobs. It is not a way to page through the feed:
cursormust be omitted (400when present).batch_size,stable_scananddescription_formatare ignored: the preview always returns up to 5 jobs of a stable scan, with Markdown descriptions.- Each job is a preview card: its
descriptionis cut to at most 500 characters (ending in…when cut), and itssummaryis null andqualifications,responsibilitiesandbenefitsare empty. The feed returns them in full. - The response has no
next_cursorand nohas_more.
estimated_total is the number of jobs the feed would deliver, as on
the feed’s first page. companies entries that match no company are
reported in warnings (and on X-Jobo-Warnings); when no include
entry matches, estimated_total is 0 and jobs is empty.
Previews are free: they are never billed and need no wallet balance.
They count against the same rate limit as POST /api/jobs/feed, and
have their own budget of 30 previews per account per hour (429
with Retry-After past it; JobsFeed subscribers have no such
budget). Retry only 503 (honoring Retry-After) and 429, with
bounded backoff.
To build a request by picking filters, and preview it without an API key, use the Feed Builder on jobo.world.
# Same body as the first request of POST /api/jobs/feed, without cursor.
curl -X POST "https://connect.jobo.world/api/jobs/feed/preview" \
-H "X-Api-Key: $JOBO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"job_subcategories": {"include": ["Nursing"]}, "company_is_agency": false}'import requests
url = "https://connect.jobo.world/api/jobs/feed/preview"
payload = {
"locations": [{ "country": "United States" }],
"job_subcategories": { "include": ["Nursing"] },
"company_sizes": { "include": ["201-500", "501-1000", "1001-5000", "5001-10000", "10001+"] },
"company_is_agency": False
}
headers = {
"X-Api-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-Api-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locations: [{country: 'United States'}],
job_subcategories: {include: ['Nursing']},
company_sizes: {include: ['201-500', '501-1000', '1001-5000', '5001-10000', '10001+']},
company_is_agency: false
})
};
fetch('https://connect.jobo.world/api/jobs/feed/preview', 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/preview",
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' => 'United States'
]
],
'job_subcategories' => [
'include' => [
'Nursing'
]
],
'company_sizes' => [
'include' => [
'201-500',
'501-1000',
'1001-5000',
'5001-10000',
'10001+'
]
],
'company_is_agency' => false
]),
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/preview"
payload := strings.NewReader("{\n \"locations\": [\n {\n \"country\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\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/preview")
.header("X-Api-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"locations\": [\n {\n \"country\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://connect.jobo.world/api/jobs/feed/preview")
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\": \"United States\"\n }\n ],\n \"job_subcategories\": {\n \"include\": [\n \"Nursing\"\n ]\n },\n \"company_sizes\": {\n \"include\": [\n \"201-500\",\n \"501-1000\",\n \"1001-5000\",\n \"5001-10000\",\n \"10001+\"\n ]\n },\n \"company_is_agency\": false\n}"
response = http.request(request)
puts response.read_body{
"estimated_total": 123,
"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",
"occupation": {
"id": "esco:8d3e8aaa-791b-4c75-a465-f3f827028f50",
"name": "Registered Nurse",
"category": "Healthcare",
"subcategory": "Nursing",
"isco_code": "2221",
"onet_soc_codes": [
"29-1141.00"
]
}
}
],
"warnings": [
{
"code": "companies_unmatched",
"field": "companies.include",
"message": "<string>"
}
]
}{
"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.
Leave out jobs from these ATS provider IDs (e.g. lever, workday), normalized like sources. May be combined with sources: sources: [greenhouse, lever] with exclude_sources: [lever] returns Greenhouse jobs.
Leave out jobs with these work models. Jobs whose work model is unknown are kept.
remote, hybrid, onsite Leave out jobs with these employment types. Jobs whose employment type is unknown are kept.
full-time, part-time, contract, internship, freelance, temporary Leave out jobs at these experience levels. Jobs whose experience level is unknown are kept.
intern, entry, mid, senior, lead, executive Leave out jobs whose description is in these languages, as ISO 639-1 codes; names and locales are mapped as for languages. Jobs whose language is unknown are kept.
Include/exclude companies, resolved exactly as companies on POST /api/jobs/search: each entry is a Jobo company id GUID, a website domain or URL (fedex.com) matched on the company's stored website domain, or anything else a whole company display name (FedEx), matched case-insensitively after normalization — not a partial match.
Resolved on the first page only: the cursor keeps the company ids the entries matched, so a scan's companies are fixed when it starts. Entries that match nothing are not a 400; they come back in the first page's warnings as companies_unmatched (include) or companies_exclude_unmatched (exclude), and as companies_outside_sources when the matched companies are on none of the requested sources. When no include entry matches, or it matches only companies outside sources, the first page is empty: jobs: [], has_more: false, next_cursor: null, estimated_total: 0, not billed.
Show child attributes
Show child attributes
Include/exclude filter on the job's occupation category (occupation.category, e.g. Healthcare). Exact, case-insensitive match. GET /api/occupations lists every value. Jobs without an occupation never match an include list.
Show child attributes
Show child attributes
Include/exclude filter on the job's occupation subcategory (occupation.subcategory, e.g. Nursing). Exact, case-insensitive match. GET /api/occupations lists every value.
Show child attributes
Show child attributes
Include/exclude filter on occupation id (occupation.id, e.g. esco:8d3e8aaa-791b-4c75-a465-f3f827028f50). Use ids, not names: names can improve between taxonomy releases, ids don't. GET /api/occupations lists every id.
Show child attributes
Show child attributes
Include/exclude filter on the hiring company's industries (company.industries, e.g. Software Development), matched on the whole name, case-insensitively. A job matches an include list if its company has ANY of the values, and an exclude list if it has none of them.
Show child attributes
Show child attributes
Include/exclude filter on the company's single primary industry (primary_industry on the company profile, GET /api/companies/{id}, e.g. Finance). Exact, case-insensitive match.
Show child attributes
Show child attributes
Include/exclude filter on the hiring company's business model (categories on the company profile, GET /api/companies/{id}): b2b, b2c, b2b2c, saas, marketplace, service-provider. A job matches an include list if its company has ANY of them, and an exclude list if it has none of them. Case-insensitive.
Show child attributes
Show child attributes
Include/exclude filter on the company's headcount band (company_size on the company profile, GET /api/companies/{id}). Companies of unknown size never match an include list and are kept by an exclude list. An unknown band is a 400.
Show child attributes
Show child attributes
Include/exclude filter on the company's annual revenue band (revenue on the company profile, GET /api/companies/{id}). Companies of unknown revenue never match an include list and are kept by an exclude list. An unknown band is a 400.
Show child attributes
Show child attributes
false leaves out jobs that recruitment and staffing agencies post on behalf of other employers (is_agency on the company profile, GET /api/companies/{id}); true returns only theirs. Omit or 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
Match count and the first jobs of the feed
Number of jobs POST /api/jobs/feed would deliver for the same
request, as estimated_total on its first page: exact when 1,000
or fewer jobs match, above that an estimate that can run a few
percent high. 0 when no companies.include entry matches.
Up to five jobs the feed's first page starts with, as preview
cards: each description is Markdown, cut to at most 500
characters; summary is null and qualifications,
responsibilities and benefits are empty.
5Show child attributes
Show child attributes
Non-fatal problems with the request, as on the feed's first page: e.g. a companies entry that matched no company (companies_unmatched, companies_exclude_unmatched, companies_outside_sources). Present only when there is something to report. The same codes are on the X-Jobo-Warnings response header, comma-separated.
Show child attributes
Show child attributes

