Build with our job data
JobsWorldwide exposes the same JSON endpoints our own frontend uses. Pull live listings into your own app, bot, or dashboard — free, no API key required.
No auth needed
Public GET endpoints, no API key or signup.
JSON responses
Plain array of job objects, ready to map over.
Cached & rate-friendly
Responses are cached server-side — keep polling reasonable.
Quickstart
Every endpoint returns a JSON array of job objects. No headers or auth required — just make a GET request to any URL below.
curl https://kenyajobs.vercel.app/api/remote-jobs
Authentication
The public tier requires no API key, no signup, and no auth headers — every endpoint listed below is open for read access right now.
If your use case needs higher volume than fair use allows (see below), reach out via the contact section at the bottom of this page — we're open to issuing dedicated keys with higher limits for serious integrations.
Response shape
Every job object follows the same shape regardless of endpoint or source:
[
{
"id": "remotive-123456",
"title": "Senior Backend Engineer",
"company": "Acme Inc.",
"location": "Remote — Worldwide",
"type": "Full-time",
"date": "2026-06-18T09:00:00.000Z",
"url": "https://remotive.com/remote-jobs/...",
"description": "We're looking for a backend engineer to join our small, distributed team...",
"source": "Remotive"
}
]| Field | Type | Description |
|---|---|---|
| id | string | Stable unique identifier, namespaced by source. |
| title | string | Job title as posted. |
| company | string | Hiring company or organisation name. |
| location | string | Free-text location, e.g. "Nairobi, Kenya" or "Remote". |
| type | string | Employment type, e.g. "Full-time", "Remote", "Internship". |
| date | string | ISO 8601 publish date. |
| url | string | Direct link to the original listing — always send applicants here. |
| description | string | Plain-text job description, HTML stripped. |
| source | string | Originating board, e.g. "Remotive", "BrighterMonday". |
Endpoints
Each endpoint below includes sample code in three languages, plus a live tester you can run right from this page.
/api/africa-jobsJobs aggregated from Kenyan, East African, and pan-African sources — BrighterMonday, MyJobMag, ReliefWeb, and more.
curl "https://kenyajobs.vercel.app/api/africa-jobs"
/api/remote-jobsRemote jobs from Remotive, Jobicy, and Arbeitnow.
curl "https://kenyajobs.vercel.app/api/remote-jobs"
/api/entry-level-jobsEntry-level roles sourced from The Muse and Remotive.
curl "https://kenyajobs.vercel.app/api/entry-level-jobs"
/api/graduate-jobsGraduate-programme and junior listings aggregated across multiple boards.
curl "https://kenyajobs.vercel.app/api/graduate-jobs"
/api/internship-jobsInternship listings aggregated across multiple boards.
curl "https://kenyajobs.vercel.app/api/internship-jobs"
/api/wfh-jobsWork-from-home listings aggregated across multiple boards.
curl "https://kenyajobs.vercel.app/api/wfh-jobs"
/api/search-jobsFree-text search across The Muse, Remotive, and Jobicy.
curl "https://kenyajobs.vercel.app/api/search-jobs?query=developer"
Rate limits & caching
Every endpoint sits behind a server-side stale-while-revalidate cache, plus a CDN-level Cache-Control header. Inside the fresh window you get an instant cached response with zero upstream calls; once stale, you still get an instant response while we refresh in the background — you should never see a slow request because an upstream board is slow.
| Endpoint group | Fresh window | Stale window | Notes |
|---|---|---|---|
| africa-jobs | 20 min | 2 hr | Heaviest fan-out (RSS + proxy calls), longest fresh window to protect rate limits. |
| remote-jobs / entry-level-jobs / graduate-jobs / wfh-jobs / internship-jobs | 10 min | 1 hr | Standard aggregator cache. |
| search-jobs | 5 min | — | Shorter window since results depend on the query string. |
Practical guidance: cache responses on your own side for at least 5–10 minutes. Polling more frequently than that just re-hits our cache and wastes your own requests.
Errors
Errors are returned as standard HTTP status codes. There's no custom error envelope — check the status code first.
| Status | Meaning | What to do |
|---|---|---|
| 200 | OK | Request succeeded, JSON array returned (may be empty). |
| 400 | Bad Request | A required parameter is missing, e.g. ?query= on /api/search-jobs. |
| 429 | Too Many Requests | You're polling faster than fair use allows. Back off and retry with backoff. |
| 500 | Upstream Error | All upstream sources failed for this request. We still try to serve last-known-good cached data before returning this. |
Drop-in client snippet
No official SDK package yet — but the whole API surface is small enough to wrap in one file. Copy this into your project:
// lib/jobsworldwide.js — tiny zero-dependency client
const BASE = "https://kenyajobs.vercel.app/api";
async function get(path) {
const res = await fetch(`${BASE}${path}`);
if (!res.ok) throw new Error(`JobsWorldwide API error: ${res.status}`);
return res.json();
}
export const JobsWorldwide = {
africaJobs: () => get("/africa-jobs"),
remoteJobs: (category) => get(`/remote-jobs${category ? `?category=${category}` : ""}`),
entryLevel: (page) => get(`/entry-level-jobs${page ? `?page=${page}` : ""}`),
graduateJobs: () => get("/graduate-jobs"),
internships: () => get("/internship-jobs"),
wfhJobs: () => get("/wfh-jobs"),
search: (query) => get(`/search-jobs?query=${encodeURIComponent(query)}`),
};
// Usage:
// const jobs = await JobsWorldwide.search("react developer");Changelog
Fair use
These endpoints power our own production site, so please cache results on your end and avoid polling more than once every few minutes. We reserve the right to rate-limit or block abusive traffic. For high-volume or commercial use, reach out — we're happy to talk.
Questions or feedback?
Building something interesting with the API? We'd love to hear about it.
Contact Us