Developer Resources

1. Quick Start

This page is the practical companion to the Job API Overview and Job Data Overview. It focuses on working code rather than reference tables. The three steps below get you from zero to a parsed job posting in no time.

1.1 Get an API Key

  1. Create an account: Sign up at rapidapi.com/auth/sign-up - no credit card required.
  2. Subscribe to the Basic plan: Open the Job Postings API pricing page and subscribe to the Basic plan. It is free and includes 100 free requests (1000 job postings) per month.
  3. Copy your API key: Your key appears in the RapidAPI dashboard after subscribing. Pass it as Authorization: Bearer <your-api-key> in every request header.

1.2 Make Your First Request

Fetch the first page of US software jobs for last month with cURL:

curl -X GET \
  "https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search?dateCreated=2026-05&countryCode=us&page=1" \
  -H "Authorization: Bearer <your-api-key>"

The same request in Python:

import requests

URL = "https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/search"
HEADERS = {"Authorization": "Bearer <your-api-key>"}

resp = requests.get(URL, headers=HEADERS, params={
    "dateCreated": "2026-05",
    "countryCode": "us",
    "page": 1,
})
resp.raise_for_status()
data = resp.json()

print(f"Total matching jobs: {data['totalCount']}")
for job in data["result"]:
    print(job["title"], "-", job.get("company", ""), "-", job.get("city", ""))

1.3 Parse the Result

The response has a metadata envelope and a result array. Each element is a job object whose full posting text lives in jsonLD.description as Markdown. The jsonLD object is a valid schema.org JobPosting and can be embedded directly in a webpage for structured data markup.

{
  "api": "Techmap.io Job Posting API",
  "totalCount": 48231,
  "page": 1,
  "pageSize": 10,
  "result": [
    {
      "title": "Senior Data Engineer",
      "company": "Example Corp",
      "city": "Austin",
      "countryCode": "us",
      "dateCreated": "2026-05-10T09:00:00.000Z",
      "language": "en",
      "industry": "IT",
      "workPlace": ["Hybrid"],
      "careerLevel": ["Senior"],
      "hasSalary": true,
      "minSalary": 140000,
      "skills": ["Python", "Spark", "dbt", "Airflow"],
      "isDirect": true,
      "isRecruiter": false,
      "portal": "linkedin",
      "source": "linkedin_us",
      "jsonLD": {
        "@context": "https://schema.org",
        "@type": "JobPosting",
        "title": "Senior Data Engineer",
        "description": "## About the Role\n\nWe are looking for ...",
        "url": "https://example.com/jobs/456",
        "datePosted": "2026-05-10"
      }
    }
  ]
}

2. API Reference

The Job Postings API is hosted on RapidAPI. The full OpenAPI definition is at api.techmap.io/jobs-api. Every request requires the Authorization: Bearer <your-api-key> header.

2.1 Endpoints

PathDescriptionPlan
/api/v2/jobs/searchReturns up to 10 job postings per page matching the query.All plans
/api/v2/jobs/countReturns the total count for a query without fetching job data. Use this to size a result set before paginating - it does not consume job-fetch quota.All plans
/api/v2/meta/jobs/distinctReturns all distinct values and their job counts for a given field over the last 30 days. Capped at 500 values. Useful for building filter UIs or discovering valid field values.PRO, ULTRA, MEGA
/api/v2/meta/jobs/statisticsReturns statistical summaries (total count, coverage, relative and absolute percentages) per distinct value for a given field over the last 30 days. Capped at 100 values.PRO, ULTRA, MEGA

Base host for all endpoints: https://daily-international-job-postings.p.rapidapi.com

Distinct and statistics examples

All distinct industry values in the last 30 days:

curl -X GET \
  "https://daily-international-job-postings.p.rapidapi.com/api/v2/meta/jobs/distinct?field=industry" \
  -H "Authorization: Bearer <your-api-key>"

Statistics for workPlace (remote / hybrid / onsite split):

curl -X GET \
  "https://daily-international-job-postings.p.rapidapi.com/api/v2/meta/jobs/statistics?field=workPlace" \
  -H "Authorization: Bearer <your-api-key>"

Valid field values for both endpoints: city, company, contractType, countryCode, department, industry, language, locale, occupation, skills, state, timezone, workPlace, workType, careerLevel.

2.2 Query Parameters

Note: If dateCreated is omitted, the API defaults to today minus 2 days - always set it explicitly in production. If page is omitted, the API defaults to 1.

Parameters marked search only are not available on /count.

ParameterTypeDescriptionExample
dateCreatedStringYYYY-MM for a full month or YYYY-MM-DD for a specific day. Defaults to today-2 if omitted.dateCreated=2026-05
dateCreatedMinStringStart of a date range (YYYY-MM-DD). Use with dateCreatedMax. Cannot be combined with dateCreated.dateCreatedMin=2026-05-01
dateCreatedMaxStringEnd of a date range. Use with dateCreatedMin.dateCreatedMax=2026-06-06
pageIntegerPage number starting at 1. Max ~1000 pages (~10000 results). Use cursor pagination for larger sets. (search only)page=2
cursorStringPass true to start cursor-based pagination; pass the nextCursor value from the response for subsequent pages. Cannot be combined with page. (search only)cursor=true
formatStringOutput format. Default: json. Options: json, csv, rss, atom, xml, parquet. (search only)format=csv
countryCodeStringISO 3166-1 alpha-2 country code. See the country list for all supported codes.countryCode=de
cityStringCity of the job location, as stated in the posting. Use quotes for multi-word cities.city="New York"
stateStringState or region. Free text as stated in the posting. Sparsely populated.state=TX
postCodeStringPostal or ZIP code. Sparsely populated.postCode=10001
timezoneString3-letter IANA timezone code.timezone=CET
timezoneMinIntegerMinimum UTC offset (-12 to 11). Use with timezoneMax to define a range.timezoneMin=-8
timezoneMaxIntegerMaximum UTC offset (-11 to 12). Must be greater than timezoneMin.timezoneMax=-5
geoPointLatNumberLatitude (WGS84, -90 to +90) for a geo distance search. Use with geoPointLng and geoDistance.geoPointLat=37.757
geoPointLngNumberLongitude (WGS84, -180 to +180) for a geo distance search.geoPointLng=-122.449
geoDistanceStringRadius around the geo point. Defaults to 10 km. Units: km or mi.geoDistance=50mi
geoTopLeftLatNumberLatitude of the Top-left corner of a bounding box. Cannot be combined with geo distance search.geoTopLeftLat=52.5
geoTopLeftLngNumberLongitude of the Top-left corner of a bounding box. Cannot be combined with geo distance search.geoTopLeftLng=5.5
geoBottomRightLatNumberLatitiude of the Bottom-right corner of a bounding box.geoBottomRightLat=48.0
geoBottomRightLngNumberLongitude of the Bottom-right corner of a bounding box.geoBottomRightLng=8.0
titleStringFree-text search within the job title. Supports boolean operators.title="data engineer"
skillsStringSkills, technologies, or tags. Comma-separated for OR logic.skills=Python,Spark
companyStringHiring or recruiting company name. Supports boolean operators.company=Microsoft
occupationStringNormalized occupation stem extracted from the job title. programmer matches all software developer variants; java programmer narrows further.occupation=programmer
industryStringIndustry classification. Values include: software, healthcare, finance, automotive, logistics, consulting, education, and more. Use /distinct?field=industry to get all active values.industry=healthcare
departmentStringDepartment. Values: it, sales, hr, finance, marketing, legal, tax. Sparsely populated.department=it
languageStringISO 639-1 language code of the posting text.language=de
workPlaceStringWork arrangement, only populated when stated in the original posting. Values: remote, hybrid, onsite, field, offshore.workPlace=remote
workTypeStringWork schedule. Values: fulltime, parttime, flextime, shift, fifo.workType=fulltime
contractTypeStringContract type. Values: permanent, temporary, freelance, contract, internship, apprenticeship, seasonal, commission, voluntary.contractType=permanent
careerLevelStringCareer level. Values: junior, senior, manager, director, chief, executive.careerLevel=senior
hasSalaryBooleanWhen true, filters to postings that include salary data.hasSalary=true
minSalaryNumberMinimum salary, currency-independent. Only meaningful when combined with hasSalary=true.minSalary=80000
isActiveBooleanWhen true, filters to postings where dateActive is in the future. dateActive comes from schema.org validThrough, or defaults to dateCreated + 30 days.isActive=true
isDirectBooleanWhen true, only returns postings linked directly to the hiring company (not via a job board).isDirect=true
isRecruiterBooleanFilter by whether the posting is from a recruiting firm.isRecruiter=false
portalStringSource portal key. See the portal explorer for all values.portal=linkedin
sourceStringSpecific source with country code suffix.source=linkedin_us

Example queries

  • Jobs within 50 miles of San Francisco:
    /api/v2/jobs/search?dateCreated=2026-05&geoPointLat=37.757&geoPointLng=-122.449&geoDistance=50mi
  • Senior software jobs in Germany posted in English:
    /api/v2/jobs/search?dateCreated=2026-05&countryCode=de&language=en&careerLevel=senior&title=software
  • Remote Python or Spark jobs in core US timezones (UTC-8 to UTC-5):
    /api/v2/jobs/search?dateCreated=2026-05&workPlace=remote&skills=Python,Spark&timezoneMin=-8&timezoneMax=-5
  • Jobs in southern Netherlands (bounding box below latitude 52.25):
    /api/v2/jobs/search?dateCreated=2026-05&countryCode=nl&geoTopLeftLat=52.25&geoTopLeftLng=0&geoBottomRightLat=32.25&geoBottomRightLng=10
  • How many Healthcare jobs in the UK this month:
    /api/v2/jobs/count?dateCreated=2026-05&countryCode=uk&industry=healthcare

2.3 Pagination

The /search endpoint returns 10 job postings per page. Use totalCount from the first page or run /count first to calculate the number of pages, then decide which pagination strategy fits (i.e., page-based vs. cursor-based).

Page-based pagination (Python)

Suitable for result sets up to ~10000 records. Use for targeted queries where you know the result set is manageable.

import requests

URL = "https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs"
HEADERS = {"Authorization": "Bearer <your-api-key>"}

params = {
    "dateCreated": "2026-05",
    "countryCode": "de",
    "industry": "software",
    "careerLevel": "senior",
}
page, all_jobs = 1, []

while True:
    resp = requests.get(f"{URL}/search", headers=HEADERS, params={**params, "page": page})
    resp.raise_for_status()
    data = resp.json()
    batch = data.get("result", [])
    all_jobs.extend(batch)
    if len(all_jobs) >= data["totalCount"] or not batch:
        break
    page += 1

print(f"Fetched {len(all_jobs)} jobs")

Cursor-based pagination (Python)

Use for large result sets (more than 10000 records). Pass cursor=true on the first request, then pass the nextCursor value from each response. Stop when nextCursor is absent. Cannot be combined with page.

import requests

URL = "https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs"
HEADERS = {"Authorization": "Bearer <your-api-key>"}

params = {"dateCreated": "2026-05", "countryCode": "us"}
cursor, all_jobs = "true", []

while cursor:
    resp = requests.get(f"{URL}/search", headers=HEADERS, params={**params, "cursor": cursor})
    resp.raise_for_status()
    data = resp.json()
    all_jobs.extend(data.get("result", []))
    cursor = data.get("nextCursor")  # absent on the last page

print(f"Fetched {len(all_jobs)} jobs")

For recurring bulk access to all jobs in a country, the Data Feeds are more cost-effective than paginating the API - one daily file contains all postings for that country and date.

Using /count for analytics (Python)

Count postings by country without fetching any job data:

import requests

URL = "https://daily-international-job-postings.p.rapidapi.com/api/v2/jobs/count"
HEADERS = {"Authorization": "Bearer <your-api-key>"}

for country in ["us", "de", "gb", "fr", "in"]:
    resp = requests.get(URL, headers=HEADERS, params={
        "dateCreated": "2026-05",
        "countryCode": country,
        "industry": "software",
    })
    print(f"{country}: {resp.json().get('totalCount', 0)} software jobs in 2026-05")

2.4 Boolean Operators

Text parameters (title, skills, company, industry, occupation) support boolean operators for precise filtering:

OperatorSyntaxExample
OR (default)Comma-separatedskills=Python,Spark - postings mentioning Python or Spark
AND%2B prefix (URL-encoded +)skills=%2BPython,%2BSpark - must mention both
NOT- prefixtitle=engineer,-junior - engineers but not juniors
Exact phraseDouble quotestitle="data engineer" - matches the exact phrase

Combined example - senior data engineers who know both Python and SQL, excluding data scientists:

title="data engineer",-scientist&careerLevel=senior&skills=%2BPython,%2BSQL

3. Data Feeds

Data Feeds and Historical Datasets are distributed as gzip-compressed JSON Lines files via AWS Data Exchange. Files follow the naming pattern techmap-jobs_{countryCode}_{date}.json.gz and contain one JSON object per line. For the export field schema and data samples see the Job Data Overview.

3.1 Finding Your Files

After subscribing on AWS Data Exchange, AWS grants read access to an S3 bucket path. To find your BUCKET_ALIAS and key prefix:

  1. Open the AWS Data Exchange console and go to Entitled Data.
  2. Select your Techmap dataset and open the Assets tab.
  3. The BUCKET_ALIAS and key prefix (e.g., us/) are shown there. Copy both - you will need them in the commands below.

If you have a direct S3 contract with Techmap rather than an ADX subscription, see section 3.2b for the corresponding commands.

To test the workflow before subscribing, the Luxembourg dataset is available for free and covers postings from January 2020 onwards.

3.2 Downloading with the AWS CLI

3.2a AWS Data Exchange subscribers

ADX requires the --request-payer requester flag on all S3 commands. List all files available for the US country prefix:

aws s3api list-objects-v2 \
  --request-payer requester \
  --bucket BUCKET_ALIAS \
  --prefix us/

Download a specific daily file:

aws s3api get-object \
  --request-payer requester \
  --bucket BUCKET_ALIAS \
  --key us/techmap-jobs_us_2026-06-06.json.gz \
  techmap-jobs_us_2026-06-06.json.gz

3.2b Direct S3 access (proprietary contracts)

Techmap provides AWS credentials for direct S3 access. Configure them as a named profile to keep them separate from your default credentials:

# List all available country prefixes
aws s3 ls --profile techmap-data s3://BUCKET_NAME/

# List all files for the US
aws s3 ls --profile techmap-data s3://BUCKET_NAME/us/

# Download a specific daily file
aws s3 cp --profile techmap-data \
  s3://BUCKET_NAME/us/techmap-jobs_us_2026-06-06.json.gz .

# Download all US files for a given month
aws s3 sync --profile techmap-data s3://BUCKET_NAME/us/ . \
  --exclude "*" --include "techmap-jobs_us_2026-05-*"

3.3 Reading .json.gz Files

Each line in the decompressed file is a self-contained JSON object. The examples below decompress on the fly without writing a temporary file.

Python

import gzip
import json

with gzip.open("techmap-jobs_us_2026-06-06.json.gz", "rt", encoding="utf-8") as fh:
    for line in fh:
        job = json.loads(line)
        title = job.get("name", "")
        company = (job.get("company") or {}).get("name", "")
        country = job.get("sourceCC", "")
        date_created = job.get("dateCreated", "")
        text = job.get("text", "")  # full posting text
        print(title, "-", company, "-", country, "-", date_created)

JavaScript / Node.js

const fs = require('fs');
const zlib = require('zlib');
const readline = require('readline');

const stream = fs.createReadStream('techmap-jobs_us_2026-06-06.json.gz')
  .pipe(zlib.createGunzip());

const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });

rl.on('line', (line) => {
  try {
    const job = JSON.parse(line);
    const company = job.company?.name ?? '';
    console.log(job.name, '-', company, '-', job.dateCreated);
  } catch (err) {
    console.error('Parse error:', err.message);
  }
});

Java (Jackson)

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import java.util.zip.GZIPInputStream;

ObjectMapper mapper = new ObjectMapper();

try (InputStream fis = new FileInputStream("techmap-jobs_us_2026-06-06.json.gz");
     GZIPInputStream gis = new GZIPInputStream(fis);
     BufferedReader reader = new BufferedReader(new InputStreamReader(gis, "UTF-8"))) {

    String line;
    while ((line = reader.readLine()) != null) {
        JsonNode job = mapper.readTree(line);
        String title = job.path("name").asText();
        String company = job.path("company").path("name").asText();
        String dateCreated = job.path("dateCreated").asText();
        System.out.println(title + " - " + company + " - " + dateCreated);
    }
}

4. References

Questions? Contact us if something is unclear or if you want sample data.