TheirStack and BetterJobs share a filter style: field names with suffixes such as _or and _not. Most queries translate line by line. The bigger changes are billing (re-reads are free) and the response shape (one canonical job with sources[]).
TheirStack is also one of the six providers behind BetterJobs. You can keep it in the mix and add the others with the same request.
Your TheirStack job search body (illustrative; built from the field names and suffix grammar in TheirStack docs, so check exact names against your code):
{
"job_title_or": ["Head of RevOps", "Head of Revenue Operations"],
Re-reads are free. Per TheirStack docs, fetching the same job again is billed again, which is why you filter on discovered_at_gte. On BetterJobs, a job you already paid for comes back free and is counted in metadata.jobs_already_paid. Overlapping windows cost nothing.
Duplicates across providers are free. If TheirStack and another source report the same opening, you pay 1 credit for the canonical job. metadata.duplicates_merged counts the folded records.
Company lookups are a different product. TheirStack charges 3 credits per company (per its docs) for company data. BetterJobs charges 1 credit per hiring profile: open jobs, is_hiring, hiring_pulse, top job families. No firmographics.
Proof of charge.GET /v1/billing/ledger?job_id=... shows when each job was charged and every free re-read.
TheirStack is a partner provider: Growth includes two partner providers, Pro and above include all six. To keep TheirStack in your results, check GET /v1/providers for enabled_on_your_plan. On Scale you can bring your own provider keys. Plans are on Credits and billing.
Base URL, auth and version header.https://api.betterjobs.cc/v1, Authorization: Bearer bj_live_..., BetterJobs-Version: 2026-10-01. See Authentication.
Wrap filters. Move filters into filters and rename them with the table above.
Drop the re-fetch guard. Remove discovered_at_gte bookkeeping that only existed to avoid paying twice. Use posted_within_days with a day of overlap. See Sync patterns.
Key on the canonical id. Store job_... ids. Keep the TheirStack id from sources[].provider_job_id only if you need to join old rows.
Rename webhook handlers.job.new becomes job.opened, job.closed stays job.closed. Add a no-op for job.reposted: it must not start outreach. company.new has no equivalent. See Detect hiring changes.
Handle partial results. A provider timeout returns 200 with metadata.status: partial. Log metadata.providers.failed; do not treat it as an error.
If downstream code expects TheirStack field names, adapt each job at the edge: