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

Migrate from Techmap

How do I translate my Techmap queries and fields to BetterJobs?

View .md

Techmap (jobdatafeeds.com) sells high-volume job feeds: an API priced per thousand jobs, daily country files and a /count endpoint to estimate cost. BetterJobs replaces the feed-and-dedup work with one search that merges Techmap and up to six other sources into canonical jobs.

Techmap is one of the six providers behind BetterJobs, so its postings can still reach you through the waterfall.

Techmap

techmap

High-volume job feeds from ATSs, job boards and public employment offices (jobdatafeeds.com).

Sources
200+ sources incl. 120 ATSs and 28 public employment offices
New postings
About 8M per month
History
451M+ postings since 2020
Countries
Claims 250 countries (about 125 with more than 100 jobs per month)
Feeds
Daily country feeds via AWS Data Exchange
API
$1 per 1k jobs; /count endpoint estimates cost

Growth includes 2 partner providers; Pro and above include all six. GET /v1/providers shows what your plan enables.

Facts per Techmap (jobdatafeeds.com).

Provider docs ↗

Topic Techmap (per Techmap) BetterJobs
Delivery API, plus daily country feeds via AWS Data Exchange API: sync search (100 jobs per page) and async search (up to 10,000 jobs)
Estimate before you pay /count endpoint dry_run: true, free
Price $1 per 1,000 jobs via the API 1 credit per unique job; dollar value depends on your plan (below)
Duplicates isDuplicate flag on records Merged into one canonical job; every source in sources[]; duplicates free
Formats json, csv, rss, parquet JSON API. CSV on Growth and above. No parquet or RSS in v1 preview
Raw posting markup jsonLD (schema.org JobPosting) Normalized fields only. No JSON-LD passthrough
History 451M+ postings since 2020 posted_within_days up to 365, include_closed: true for closed jobs

Before: pull a feed or API page, estimate with /count, drop flagged duplicates, normalize. techmap_count and techmap_fetch stand for your existing wrappers.

# Before (Techmap): estimate, fetch, then dedup and normalize yourself
cost = techmap_count(query) # /count estimates cost, per Techmap
rows = techmap_fetch(query) # $1 per 1k jobs, per Techmap
rows = [r for r in rows if not r["isDuplicate"]]
jobs = [normalize(r["jsonLD"]) for r in rows] # your own mapping from schema.org JobPosting

After: estimate free, then fetch merged canonical jobs with a credit cap.

Terminal window
# Free estimate (replaces /count)
curl https://api.betterjobs.cc/v1/jobs/search \
-H "Authorization: Bearer $BETTERJOBS_API_KEY" \
-H "BetterJobs-Version: 2026-10-01" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"title_or": ["Warehouse Manager", "Logistics Manager"],
"country_code_or": ["DE"],
"employment_type_or": ["full_time"],
"posted_within_days": 1
},
"waterfall": { "strategy": "max_coverage" },
"limit": 100,
"dry_run": true
}'
# Fetch merged jobs (replaces fetch + isDuplicate filter + normalize)
curl https://api.betterjobs.cc/v1/jobs/search \
-H "Authorization: Bearer $BETTERJOBS_API_KEY" \
-H "BetterJobs-Version: 2026-10-01" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"title_or": ["Warehouse Manager", "Logistics Manager"],
"country_code_or": ["DE"],
"employment_type_or": ["full_time"],
"posted_within_days": 1
},
"waterfall": { "strategy": "max_coverage", "max_credits": 100 },
"limit": 100
}'

A daily country file becomes a daily search per country with one day of overlap:

{
"filters": { "country_code_or": ["DE"], "posted_within_days": 2 },
"waterfall": { "strategy": "max_coverage", "max_credits": 10000 },
"limit": 10000
}

Send it to POST /v1/searches (async, up to 10,000 jobs), read the pages for free and upsert on id. Jobs from the overlap day that you already paid for are free. Add a search watch with job.closed to mark expired jobs, also free. The full recipe is on Sync patterns.

Field names in Techmap records and their BetterJobs equivalents. Rows show only fields with a confident one-to-one match.

— = no confident one-to-one equivalent in that provider's published field names.
BetterJobsTechmap
employment_typecontractType

Other Techmap fields, per its reference, and where that information lives in BetterJobs:

Techmap field BetterJobs Note
isDuplicate none needed Duplicates are merged. sources[] lists every source that saw the job
jsonLD the canonical job fields Normalized, not passed through. See the field dictionary
dateActive — No confident equivalent. Compare with first_seen_at, last_seen_at, last_verified_at
workPlace — No confident equivalent. Compare with location.* and location.remote
  1. Per unique job, not per row. Techmap prices by jobs delivered ($1 per 1,000 via the API, per Techmap). BetterJobs charges 1 credit per unique canonical job. Records from other sources that describe the same opening are merged for free.

  2. Re-reads are free. A job you already paid for returns free in later searches. Overlapping daily windows cost nothing extra.

  3. Estimates are free in both. /count on Techmap, dry_run on BetterJobs.

  4. Proof of charge. GET /v1/billing/ledger?job_id=... lists each charge and each free re-read.

Techmap is a partner provider: Growth includes two partner providers, Pro and above include all six. GET /v1/providers shows whether your plan enables techmap. Plans are on Credits and billing.

  1. Replace file ingestion with API pages. Async search plus cursor paging replaces downloading daily files.

  2. Delete the dedup step. No isDuplicate filter. Key rows on the canonical id.

  3. Delete your JSON-LD mapping. Read normalized fields such as title, location, employment_type, salary directly.

  4. Map contractType to employment_type. Values are full_time, part_time, contract, internship, temporary or null. See Taxonomies.

  5. Handle closures with events. Use job.closed from a watch instead of diffing daily files. See Detect hiring changes.

  • posted_within_days counts from first_seen_at. It is the earliest sighting across all sources.
  • No parquet in v1 preview. Write the JSON pages to parquet yourself if your warehouse needs it.
  • null is unknown. employment_type: null means no source said, not “other”.