# Careerjet API: v4 Endpoint, Publisher Key, Limits & Examples

> How the Careerjet v4 job search API works: publisher key, Basic auth, the required user_ip and user_agent, every field, and curl, JS and Python code.

Source: https://cleanjobdata.com/articles/careerjet-api-guide
Published: 2026-11-01

TL;DR: Careerjet's job search API is one call: GET https://search.api.careerjet.net/v4/query, authenticated with HTTP Basic auth where your publisher API key is the username and the password is empty. Every request must include the IP address and user agent of the end user who triggered it, so the API is built for showing Careerjet results to visitors on your own site. Keys come from a Careerjet publisher account, one per publisher website. Careerjet's API docs don't publish rate limits or pricing.

The Careerjet API is one search endpoint: send `GET https://search.api.careerjet.net/v4/query` with HTTP Basic auth, your publisher API key as the username and an empty password, and you get matching jobs back as JSON. Every call must also carry `user_ip` and `user_agent`, the IP address and user agent of the person whose action triggered the search. You get the key from a Careerjet publisher account, and each publisher website needs its own key.

Careerjet is a job search engine that aggregates listings across many countries. Its API sits inside a publisher program whose pitch is to "monetize your web traffic by displaying Careerjet's job listings," alongside ready-made widgets and XML feeds. This guide covers getting a key, the full request and response, working code, and the limits that matter before you build on it. Everything here was checked against Careerjet's own pages on November 1, 2026.

## At a Glance

| | |
|---|---|
| Endpoint | `GET https://search.api.careerjet.net/v4/query` |
| Auth | HTTP Basic: API key as username, empty password |
| Required fields | `user_ip`, `user_agent` (of your end user) |
| Market | `locale_code`, such as `en_US`; defaults to `en_GB` |
| Page size | `page_size` 1 to 100, default 20 |
| Keys | One per publisher website, from a publisher account |
| Rate limits and pricing | Not published in the API docs |
| Description | Excerpt only, 120 characters by default |

## How to Get a Careerjet API Key

Register as a publisher at [careerjet.com/partners/register/as-publisher](https://www.careerjet.com/partners/register/as-publisher). Careerjet's API docs say each publisher website needs its own API key, which you get from your Publisher account. If you run several sites, plan for several keys.

The publisher program also offers widgets (a JobBox and a SearchBox you customize and paste into a page) and XML feeds. The API is pitched at "more advanced webmasters" who want Careerjet results inside their own design.

Older tutorials and client libraries describe an earlier version of the API. The current documentation only covers v4 at `search.api.careerjet.net`, so use that.

## The Endpoint

There's one call. The key goes in a Basic auth header and everything else goes in the query string:

```bash
curl -s -u "YOUR_API_KEY:" \
  "https://search.api.careerjet.net/v4/query?locale_code=en_US&keywords=python+developer&location=New+York&user_ip=203.0.113.7&user_agent=Mozilla%2F5.0"
```

The trailing colon after the key in `-u` is the empty password. Careerjet's own curl example also sends a Referer header (`-e`) set to the publisher page where the search ran, which fits the API's purpose: each call is meant to represent a real visitor's search on your site.

## Request Fields

| Field | Required | Notes |
|---|---|---|
| `user_ip` | Yes | IP address of the user whose action triggered the call |
| `user_agent` | Yes | User agent string of that same user |
| `keywords` | No | One or more URL-encoded search terms |
| `location` | No | Free-text location; leave it out to search the whole country |
| `locale_code` | No | `[language]_[COUNTRY]`, such as `en_US`; defaults to `en_GB` and must be a supported locale |
| `contract_type` | No | `p` permanent, `c` contract, `t` temporary, `i` internship or training, `v` volunteering |
| `work_hours` | No | `f` full-time, `p` part-time |
| `sort` | No | `relevance` (default), `date` or `salary` |
| `page` | No | 1 to 10 |
| `page_size` | No | 1 to 100, default 20 |
| `offset` | No | Integer; the docs give a range of 1 to 999 and a default of 0 |
| `radius` | No | Search radius around `location`, default 5, in km or miles depending on the location |
| `fragment_size` | No | Length of the description excerpt in characters, default 120 |

The docs say `locale_code` must be on a list of supported locales but don't print the list. `en_GB` (the default) and `en_US` (used in Careerjet's own example) are safe; test any other market before you rely on it.

## The Response

A successful search returns `type: "JOBS"` with counts and a `jobs` array. The top-level fields are Careerjet's; the job values below are illustrative:

```json
{
  "type": "JOBS",
  "hits": 62,
  "message": "62 matching jobs found",
  "pages": 4,
  "response_time": 0.322,
  "jobs": [
    {
      "title": "Python Developer",
      "company": "Acme Inc",
      "date": "Wed, 28 Oct 2026 19:13:43 GMT",
      "description": "...building data pipelines in Python for our analytics team...",
      "locations": "New York, NY",
      "salary": "$120,000 - $150,000 per year",
      "salary_currency_code": "USD",
      "salary_min": 120000,
      "salary_max": 150000,
      "salary_type": "Y",
      "url": "https://..."
    }
  ]
}
```

| Field | What it is |
|---|---|
| `type` | `JOBS` for results, `LOCATIONS` when the location couldn't be resolved (see below) |
| `hits` | Total matching jobs |
| `pages` | Number of result pages |
| `message` | Human-readable summary |
| `response_time` | Server time in seconds |
| `title`, `company` | Job title and company name |
| `date` | Posting date as an HTTP-style date string |
| `description` | An excerpt, not the full posting; length set by `fragment_size` |
| `locations` | Location as display text |
| `salary` | Salary as text, when the listing has one |
| `salary_min`, `salary_max`, `salary_currency_code` | Parsed salary range and currency |
| `salary_type` | `Y` yearly, `M` monthly, `W` weekly, `D` daily, `H` hourly |
| `url` | Link to the job |

### Location mode

If Careerjet can't run a search for the `location` you sent, it returns `type: "LOCATIONS"` instead of jobs. An empty `locations` array comes with the message "no matching location found"; a list of strings means "multiple locations found" and you should ask the user to pick one, then search again with that exact string. Handle this branch, or ambiguous city names will look like empty results.

## Code Examples

### JavaScript (Node 18+)

```javascript
const CAREERJET_KEY = process.env.CAREERJET_API_KEY;
const auth = "Basic " + Buffer.from(`${CAREERJET_KEY}:`).toString("base64");

// Pass the end user's IP and user agent from the incoming request.
async function searchCareerjet({ keywords, location, userIp, userAgent, page = 1 }) {
  const params = new URLSearchParams({
    locale_code: "en_US",
    keywords,
    location,
    page: String(page),
    page_size: "50",
    user_ip: userIp,
    user_agent: userAgent,
  });

  const res = await fetch(`https://search.api.careerjet.net/v4/query?${params}`, {
    headers: { Authorization: auth },
  });
  if (!res.ok) throw new Error(`Careerjet API error: ${res.status}`);

  const body = await res.json();
  if (body.type === "LOCATIONS") {
    return { hits: 0, jobs: [], locationChoices: body.locations };
  }
  return { hits: body.hits, pages: body.pages, jobs: body.jobs };
}
```

### Python

```python
import os
import requests

CAREERJET_KEY = os.environ["CAREERJET_API_KEY"]

def search_careerjet(keywords: str, location: str, user_ip: str, user_agent: str, page: int = 1) -> dict:
    res = requests.get(
        "https://search.api.careerjet.net/v4/query",
        params={
            "locale_code": "en_US",
            "keywords": keywords,
            "location": location,
            "page": page,
            "page_size": 50,
            "user_ip": user_ip,
            "user_agent": user_agent,
        },
        auth=(CAREERJET_KEY, ""),  # key as username, empty password
        timeout=30,
    )
    res.raise_for_status()
    body = res.json()
    if body["type"] == "LOCATIONS":
        return {"hits": 0, "jobs": [], "location_choices": body["locations"]}
    return {"hits": body["hits"], "pages": body["pages"], "jobs": body["jobs"]}
```

In a web app, take `user_ip` and `user_agent` from the visitor's request (behind a proxy, from the forwarded-for header your proxy sets), not from your server.

## Paging Through Results

Use `page_size` (up to 100) and `page`, and read `pages` from the first response to know how many pages exist. The docs cap `page` at 10 and list a separate `offset` parameter, but they don't explain how `page` and `offset` interact, so test deep paging before you depend on it.

Because each call is supposed to carry a real visitor's IP and user agent, paging should follow what a user actually asks for. The API isn't designed for crawling Careerjet's whole index from a server.

## Errors

Careerjet documents two specific errors:

| Status | Meaning |
|---|---|
| 400 | "Unsupported locale code" |
| 403 | "Missing param user_ip or user_agent" |

Other errors come back with a short body giving the error type and details. A wrong or missing key fails at the Basic auth step, so check the key and the trailing empty password first.

## Limits and Pricing

Careerjet's API documentation doesn't publish rate limits, quotas, pricing or usage terms, and its publisher page doesn't either. The program is framed as a way for publishers to earn from traffic they send to Careerjet's listings, so the terms you agree to at signup are the ones that apply. Read them before building, and ask Careerjet directly if you need a number.

## What the Careerjet API Doesn't Give You

- **Full descriptions.** `description` is an excerpt, 120 characters by default; the full posting is behind `url`.
- **Server-side or bulk access by design.** The required `user_ip` and `user_agent` tie every call to a real visitor, which doesn't fit background jobs, analytics pipelines or building your own index.
- **Structured location.** `locations` is display text, with no city, state or country IDs and no coordinates.
- **A remote filter or seniority field.** Neither is documented.
- **Company data.** Only a company name: no logo, website or size.
- **Published limits and prices.** You only learn them through the publisher program.

## Alternatives

- [CleanJobData vs Careerjet](https://cleanjobdata.com/vs/careerjet-api): a side-by-side with an API that sources jobs directly from employer ATS platforms and career sites, with a self-serve key and published pricing.
- [The Jooble API](https://cleanjobdata.com/articles/jooble-api-guide): another aggregator's publisher-style API, with a POST endpoint and a 500-request lifetime cap on the free plan.
- [The best free job APIs in 2026](https://cleanjobdata.com/articles/best-free-job-apis-2026): every free option we've tested, including ones that need no key.

## FAQ

### Is the Careerjet API free?

Careerjet doesn't publish a price for the API. Access comes through its publisher program, which is pitched as a way to earn from displaying Careerjet's listings. Check the terms in your publisher account for what applies to you.

### How do I get a Careerjet API key?

Register as a publisher at careerjet.com/partners/register/as-publisher. Each publisher website needs its own key, which you find in your Publisher account.

### How does Careerjet API authentication work?

HTTP Basic auth. The API key is the username and the password is an empty string, so the header is `Authorization: Basic` followed by the Base64 encoding of `YOUR_KEY:`.

### Why does the Careerjet API need user_ip and user_agent?

Careerjet's docs mark both as required: they're the IP address and user agent of the user whose action triggered the call. Leave either out and you get a 403. In practice it means each search should come from a real visitor on your site.

### What are the Careerjet API rate limits?

They aren't published in Careerjet's API documentation. Confirm them with Careerjet or in your publisher agreement before you build on the API.

### Is there a Careerjet API alternative that works server-side?

CleanJobData is self-serve: sign up, get a key immediately, and search with GET requests and a Bearer token, with no end-user IP or user agent required. Its listings come from employer ATS platforms and career sites rather than Careerjet's index, so it isn't a copy of Careerjet's results. See the [Jobs API reference](https://cleanjobdata.com/docs/api/jobs) or try it in the [playground](https://cleanjobdata.com/playground).
