Skip to content
API v1 preview — endpoints and fields may change before general availability.

Search jobs

Search jobs. Synchronous search across the providers chosen by the waterfall strategy.

Cost: 1 credit / unique job1 credit per unique job returned that you have not already paid for.

POST
/jobs/search
curl --request POST \
--url https://api.betterjobs.cc/v1/jobs/search \
--header 'Authorization: Bearer <token>' \
--header 'BetterJobs-Version: 2026-10-01' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: 7b8f2c4e-1a3d-4f5b-9c6e-0d2a4b6c8e1f' \
--data '{ "filters": { "title_or": [ "Head of RevOps", "Head of Revenue Operations" ], "country_code_or": [ "DE", "AT", "CH" ], "posted_within_days": 7 }, "waterfall": { "strategy": "cheapest_first", "max_credits": 100, "timeout_ms": 10000 }, "limit": 25 }'

Synchronous search across the providers chosen by the waterfall strategy. Returns up to 100 canonical jobs per page. Page with next_cursor.

Send dry_run: true to get a free estimate (expected_unique_jobs_range, providers_planned, credits_range) without fetching anything.

Unknown filter fields return 400 unknown_filter. If a provider fails or timeout_ms is reached, you still get 200 with metadata.status: partial and are billed only for returned jobs.

BetterJobs-Version
string
Allowed values: 2026-10-01
Example
2026-10-01

Date-pinned API version. Changes within a version are additive only. Defaults to your account’s pinned version.

Idempotency-Key
string
<= 255 characters
Example
7b8f2c4e-1a3d-4f5b-9c6e-0d2a4b6c8e1f

Unique key (for example a UUID). Retrying with the same key and body returns the first response and never charges twice. Same key with a different body returns 409 idempotency_conflict.

Media typeapplication/json
object
filters
required

Filter grammar with suffix operators. Unknown fields return 400 unknown_filter.

object
title_or

Match any of these title keywords.

Array<string>
title_not

Exclude titles containing any of these.

Array<string>
country_code_or

ISO 3166-1 alpha-2 codes.

Array<string>
posted_within_days

Jobs first seen within this many days.

integer
>= 1 <= 365
seniority_or
Array<string>
Allowed values: intern junior mid senior lead director vp c_level
employment_type_or
Array<string>
Allowed values: full_time part_time contract internship temporary
remote

true remote only, false non-remote only, null or omitted = any.

boolean | null
salary_min_gte

Keep jobs whose salary.min is at least this value (yearly, in the job’s currency). Jobs with salary null are excluded when set.

number
company_domain_or
Array<string>
job_family_or
Array<string>
include_closed

Include jobs with status: closed.

boolean
waterfall

How BetterJobs routes the request across providers.

object
strategy

cheapest_first stops once enough unique jobs are found, starting with the BetterJobs index. freshest_first tries the sources with the fastest refresh first. max_coverage queries every provider on your plan. consensus returns only jobs seen by at least min_sources sources. own_only uses the BetterJobs index only.

string
default: cheapest_first
Allowed values: cheapest_first freshest_first max_coverage consensus own_only
providers

Override the providers to query. Must be enabled on your plan.

Array<string>
Allowed values: betterjobs reqbeat signalsapi theirstack jobspipe coresignal techmap
max_credits

Hard cap on credits this request may charge. Results stop at the cap.

integer
timeout_ms

Per-request time budget. Slow providers are dropped and the result is partial.

integer
default: 10000 >= 1000 <= 30000
min_sources

Minimum agreeing sources for consensus.

integer
default: 2 >= 2 <= 7
limit
integer
default: 25 >= 1 <= 100
cursor

next_cursor from the previous page.

string
dry_run

Return a free estimate without fetching.

boolean
Examples

Head of RevOps in DACH, last 7 days

{
"filters": {
"title_or": [
"Head of RevOps",
"Head of Revenue Operations"
],
"country_code_or": [
"DE",
"AT",
"CH"
],
"posted_within_days": 7
},
"waterfall": {
"strategy": "cheapest_first",
"max_credits": 100,
"timeout_ms": 10000
},
"limit": 25
}

Search results, or an estimate when dry_run is true.

Media typeapplication/json
One of:
object
data
required
Array<object>

A canonical job: one real opening, merged from every source that saw it. Null semantics: null = unknown; [] = verified none; field omitted = not part of this payload (for example the lifecycle-only job in job.closed and job.reposted events).

object
id
required

Canonical job id. Stable across sources and requests.

string
/^job_/
title
required
string
company
required

Company reference embedded in jobs, events and profiles.

object
id
required
string
/^cmp_/
name
required
string
domain
required

Primary web domain. null when unknown.

string | null
location
required
object
city
required
string | null
region
required
string | null
country_code
required

ISO 3166-1 alpha-2.

string | null
remote
required

true remote, false on-site or hybrid, null unknown.

boolean | null
employment_type
required
One of:
string
Allowed values: full_time part_time contract internship temporary
seniority
required
One of:
string
Allowed values: intern junior mid senior lead director vp c_level
job_family
required
string | null
salary
required
One of:
object
min
required
number | null
max
required
number | null
currency
required

ISO 4217.

string
period
required
string
Allowed values: year month hour
origin
required

declared = stated in the posting. inferred = estimated by a source.

string
Allowed values: declared inferred
description
required

Plain-text job description.

string | null
apply_url
required
string | null format: uri
posted_at
required

Date the employer posted the job, if known.

string | null format: date-time
first_seen_at
required

Earliest time any source saw the job.

string format: date-time
last_seen_at
required

Latest time any source saw the job.

string format: date-time
last_verified_at
required

Latest time the job was confirmed live at its origin.

string | null format: date-time
status
required
string
Allowed values: open closed
closed_reason
required

Why the job closed. null while open.

string | null
Allowed values: filled expired removed unknown
repost_count
required

Times the same job was re-listed.

integer
p_real
required

Probability (0-1) that the job is a real open req, from cross-source corroboration.

number
<= 1
sources
required
Array<object>

One provider’s view of the canonical job.

object
provider
required

Source slug. betterjobs is the BetterJobs index.

string
Allowed values: betterjobs reqbeat signalsapi theirstack jobspipe coresignal techmap
provider_job_id
required
string
url
required
string | null format: uri
first_seen_at
required
string format: date-time
last_seen_at
required
string format: date-time
fields
required

Job fields this source contributed to the canonical record.

Array<string>
license
required
object
display
required

You may show this job to your end users.

boolean
resale
required

You may resell or redistribute this job as data.

boolean
next_cursor
required

Pass as cursor for the next page. null = last page.

string | null
metadata
required
object
request_id
required
string
status
required

partial = at least one provider failed or timed out. You are billed only for returned jobs.

string
Allowed values: complete partial
credits_charged
required
integer
jobs_already_paid
required

Returned jobs you had already paid for (free).

integer
duplicates_merged
required

Provider records merged into existing canonical jobs (free).

integer
credits_remaining
required
integer
providers
required
object
tried
required
Array<string>
Allowed values: betterjobs reqbeat signalsapi theirstack jobspipe coresignal techmap
hit
required

Providers that returned at least one match.

Array<string>
Allowed values: betterjobs reqbeat signalsapi theirstack jobspipe coresignal techmap
failed
required
Array<object>
object
provider
required

Source slug. betterjobs is the BetterJobs index.

string
Allowed values: betterjobs reqbeat signalsapi theirstack jobspipe coresignal techmap
code
required

provider_timeout = the provider missed timeout_ms. provider_error = the provider returned an error.

string
Allowed values: provider_timeout provider_error
contributions
required

Unique jobs each provider contributed first.

object
key
additional properties
integer
field_coverage
required

Fraction (0-1) of returned jobs with a non-null value, per field.

object
key
additional properties
number
<= 1
latency_ms
required
integer
Examples

Complete result

{
"data": [
{
"id": "job_01JC8X4M2Q7RV3T9KD5W6YH0AB",
"title": "Head of Revenue Operations",
"company": {
"id": "cmp_4Rk7TzP1aQ",
"name": "Acme Robotics",
"domain": "acme-robotics.example"
},
"location": {
"city": "Berlin",
"region": "Berlin",
"country_code": "DE",
"remote": false
},
"employment_type": "full_time",
"seniority": "lead",
"job_family": "operations",
"salary": {
"min": 110000,
"max": 135000,
"currency": "EUR",
"period": "year",
"origin": "declared"
},
"description": "Acme Robotics is hiring a Head of Revenue Operations to own forecasting, CRM hygiene and the GTM tool stack across DACH.",
"apply_url": "https://jobs.acme-robotics.example/revops-lead/apply",
"posted_at": "2026-10-08T00:00:00Z",
"first_seen_at": "2026-10-08T06:40:00Z",
"last_seen_at": "2026-10-11T06:10:00Z",
"last_verified_at": "2026-10-11T06:10:00Z",
"status": "open",
"closed_reason": null,
"repost_count": 0,
"p_real": 0.94,
"sources": [
{
"provider": "betterjobs",
"provider_job_id": "bj_idx_5521907",
"url": "https://jobs.acme-robotics.example/revops-lead",
"first_seen_at": "2026-10-08T06:40:00Z",
"last_seen_at": "2026-10-11T06:10:00Z",
"fields": [
"title",
"description",
"apply_url",
"location",
"employment_type",
"posted_at"
]
},
{
"provider": "theirstack",
"provider_job_id": "ts_88213377",
"url": "https://jobs.acme-robotics.example/revops-lead",
"first_seen_at": "2026-10-08T07:12:00Z",
"last_seen_at": "2026-10-11T04:02:00Z",
"fields": [
"salary",
"seniority"
]
},
{
"provider": "techmap",
"provider_job_id": "tm_3f9a2c71",
"url": "https://boards.example/acme-robotics/revops-lead",
"first_seen_at": "2026-10-08T09:30:00Z",
"last_seen_at": "2026-10-10T23:40:00Z",
"fields": [
"job_family"
]
}
],
"license": {
"display": true,
"resale": false
}
}
],
"next_cursor": "cur_8fJ2kQ",
"metadata": {
"request_id": "req_7Hc2LmQ9xT",
"status": "complete",
"credits_charged": 1,
"jobs_already_paid": 0,
"duplicates_merged": 2,
"credits_remaining": 9841,
"providers": {
"tried": [
"betterjobs",
"techmap",
"theirstack"
],
"hit": [
"betterjobs",
"techmap",
"theirstack"
],
"failed": [],
"contributions": {
"betterjobs": 1,
"techmap": 0,
"theirstack": 0
}
},
"field_coverage": {
"salary": 1,
"seniority": 1,
"location.remote": 1,
"description": 1
},
"latency_ms": 1840
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

X-Credits-Charged
integer
Example
1

Credits charged by this request.

X-Credits-Remaining
integer
Example
9841

Credits left on your account after this request.

RateLimit-Limit
integer
Example
60

Requests allowed in the current window.

RateLimit-Remaining
integer
Example
59

Requests left in the current window.

RateLimit-Reset
integer
Example
42

Seconds until the window resets.

BetterJobs-Version
string
Example
2026-10-01

API version used to serve this request.

Invalid request (invalid_request) or unknown filter field (unknown_filter).

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples

unknown_filter

{
"error": {
"type": "invalid_request_error",
"code": "unknown_filter",
"message": "Unknown filter field 'job_title_or'. Did you mean 'title_or'?",
"param": "filters.job_title_or",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#unknown_filter",
"request_id": "req_4Bn8CxV2zA"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Missing or invalid API key.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
Exampleunauthorized
{
"error": {
"type": "authentication_error",
"code": "unauthorized",
"message": "Missing or invalid API key. Send 'Authorization Bearer bj_live_...'.",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#unauthorized",
"request_id": "req_5Dl6EvN0xY"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Not enough credits for this request.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
ExampleinsufficientCredits
{
"error": {
"type": "billing_error",
"code": "insufficient_credits",
"message": "This request needs at least 25 credits; 3 remain.",
"credits_needed": 25,
"upgrade_url": "https://betterjobs.cc/pricing",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#insufficient_credits",
"request_id": "req_6Ek5FuM9wX"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Your plan does not include this feature or provider.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
ExampleplanRequired
{
"error": {
"type": "permission_error",
"code": "plan_required",
"message": "Provider 'coresignal' is not enabled on your plan. Pro and above include all six providers.",
"required_plan": "pro",
"upgrade_url": "https://betterjobs.cc/pricing",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#plan_required",
"request_id": "req_7Fj4GtL8vW"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Same Idempotency-Key reused with a different body.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
ExampleidempotencyConflict
{
"error": {
"type": "conflict_error",
"code": "idempotency_conflict",
"message": "Idempotency-Key '7b8f2c4e-1a3d-4f5b-9c6e-0d2a4b6c8e1f' was used with a different request body.",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#idempotency_conflict",
"request_id": "req_9Hh2IrJ6tU"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Too many requests. Wait Retry-After seconds.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
ExamplerateLimited
{
"error": {
"type": "rate_limit_error",
"code": "rate_limited",
"message": "Rate limit exceeded. Retry after 12 seconds.",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#rate_limited",
"request_id": "req_0Ig1JqH5sT"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.

Retry-After
integer
Example
12

Seconds to wait before retrying.

RateLimit-Limit
integer
Example
60

Requests allowed in the current window.

RateLimit-Remaining
integer
Example
59

Requests left in the current window.

RateLimit-Reset
integer
Example
42

Seconds until the window resets.

Something failed on our side. Safe to retry with the same Idempotency-Key.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: invalid_request_error authentication_error billing_error permission_error not_found_error conflict_error rate_limit_error api_error
code
required
string
Allowed values: invalid_request unknown_filter unauthorized insufficient_credits plan_required not_found idempotency_conflict rate_limited internal_error
message
required
string
doc_url
required
string format: uri
request_id
required
string
credits_needed

Present on insufficient_credits.

integer
required_plan
string
Allowed values: free starter growth pro scale enterprise
upgrade_url

Present on insufficient_credits and plan_required.

string format: uri
param

Offending field on invalid_request and unknown_filter.

string
key
additional properties
any
Examples
ExampleinternalError
{
"error": {
"type": "api_error",
"code": "internal_error",
"message": "Unexpected error. Retry with the same Idempotency-Key; you will not be charged twice.",
"doc_url": "https://docs.betterjobs.cc/platform/errors/#internal_error",
"request_id": "req_1Jf0KpG4rS"
}
}
X-Request-Id
string
Example
req_7Hc2LmQ9xT

Unique id for this request. Quote it to support.