# AWS Data Exchange

Pay per request through your AWS bill - called with the AWS SDK or CLI and your own AWS credentials.

The Job Postings API is also available on [AWS Data Exchange](https://aws.amazon.com/marketplace/pp/prodview-uo3hwys7qepk6) - billed through your AWS bill and called with your own AWS credentials. The RSS Feed API is only available on RapidAPI.

## Products and prices

| Product | Price | Data |
| --- | --- | --- |
| [Techmap Job Postings API - Search & Count Daily Global Job Data](https://aws.amazon.com/marketplace/pp/prodview-uo3hwys7qepk6) | 0.010 USD per successful request (10 job postings), no monthly fee | All countries |
| [Techmap Job Postings API - Free Test (Luxembourg)](https://aws.amazon.com/marketplace/pp/prodview-xgdo5aq5ejxts) | Free (fair use: 1,000 requests per AWS account and day) | Luxembourg (`countryCode=lu`) |

1,000 job postings cost 1.00 USD. Subscribing requires a short verification form (an AWS requirement). Same endpoints, filters and fields as on RapidAPI; Parquet is not offered on AWS Data Exchange.

## Using the API

Search and count daily job postings from 200+ job portals, ATS career pages and employment offices in 200+ countries, updated hourly. A search request returns 10 job postings; every successful request is billed.

**Test product:** returns all job postings from Luxembourg. Requests with another `countryCode` return 400. Fair use: up to 1,000 requests per AWS account per day and 2 requests per second for all test subscribers together.

### How to call the API

You call the API through AWS Data Exchange (`SendApiAsset`) in region `eu-central-1`, signed with your AWS credentials. Your IAM user or role needs the permission `dataexchange:SendApiAsset`. Copy the data set, revision and asset IDs from the API asset of your entitled data set.

**AWS CLI**

```bash
aws dataexchange send-api-asset --region eu-central-1 \
  --data-set-id <DATA_SET_ID> --revision-id <REVISION_ID> --asset-id <ASSET_ID> \
  --method GET --path "/api/v2/jobs/search" \
  --query-string-parameters "countryCode=lu,dateCreated=2026-10-13"
```

**Python (boto3)**

```python
import boto3, json

adx = boto3.client("dataexchange", region_name="eu-central-1")
response = adx.send_api_asset(
    DataSetId="<DATA_SET_ID>", RevisionId="<REVISION_ID>", AssetId="<ASSET_ID>",
    Method="GET", Path="/api/v2/jobs/search",
    QueryStringParameters={"countryCode": "lu", "dateCreated": "2026-10-13"},
)
jobs = json.loads(response["Body"])
print(jobs["totalCount"], [j["title"] for j in jobs["result"]])
```

**JavaScript (AWS SDK v3)**

```js
import { DataExchangeClient, SendApiAssetCommand } from "@aws-sdk/client-dataexchange";

const adx = new DataExchangeClient({ region: "eu-central-1" });
const response = await adx.send(new SendApiAssetCommand({
  DataSetId: "<DATA_SET_ID>", RevisionId: "<REVISION_ID>", AssetId: "<ASSET_ID>",
  Method: "GET", Path: "/api/v2/jobs/count",
  QueryStringParameters: { countryCode: "lu", dateCreated: "2026-10" },
}));
console.log(JSON.parse(response.Body).totalCount);
```

### Endpoints

| Endpoint | Purpose |
| --- | --- |
| `/api/v2/jobs/search` | Job postings for a query, 10 per request (`page` or `cursor` for more) |
| `/api/v2/jobs/count` | Number of job postings for the same query |
| `/api/v2/meta/jobs/distinct` | Distinct values of a field (e.g. `field=industry`) |
| `/api/v2/meta/jobs/statistics` | Coverage and value distribution of a field |

Formats: `json` (default), `csv`, `rss`, `atom`, `xml`. Parameters, fields and examples: https://api.techmap.io/jobs-api

### Errors

Errors return JSON `{"message": "..."}`: **400** invalid parameter, **403** access denied by AWS Data Exchange (e.g. no active subscription), **429** too many requests (retry with backoff; in the test product also when the daily fair-use limit is reached), **503** search backend temporarily unavailable or incomplete (retry later). A 200 response is always complete.

Support: data@techmap.io
