For developers API v1
Put remote opportunities into your job board, community, or internal tool. Free access, useful filters, and structured JSON.
No signup. No API key. Just a GET request.
/api/v1/jobs?category=programming&limit=1{
"data": [
{
"title": "Senior Frontend Engineer",
"company": {
"name": "Acme Corp"
},
"location": "Remote (Worldwide)",
"type": "Full-time",
"employment_types": [
"FULL_TIME"
],
"employer_job_id": null,
"direct_apply": null
}
],
"pagination": {
"limit": 1,
"offset": 0,
"has_more": true
}
}Choose a category and job type to bring relevant opportunities to your audience.
Find roles by keyword and link members to the full listing and application page.
Work with structured job, company, location, and salary fields in your app or dashboard.
01 / Quickstart
Choose the jobs you want, update the request, then copy an example into your project.
https://remotejobs.org/api/v1/jobscurl --fail 'https://remotejobs.org/api/v1/jobs?category=programming&limit=20&offset=0'JavaScript and Python examples run on your server. Cross-origin browser requests aren’t currently supported.
Open JSON response02 / Query parameters
All parameters are optional. Combine them to narrow your results; active jobs are returned newest first.
| Parameter | Default | How it works |
|---|---|---|
categorystring | All categories | A category slug, such as programming or design. Unknown slugs return an empty page. See available values below. |
typestring | All types | full-time, part-time, contract, or freelance. |
qstring | No search | English full-text search across job titles and descriptions. URL-encode your search terms. |
limitinteger | 20 | Jobs per request, from 1 to 50. |
offsetinteger | 0 | Number of jobs to skip. Use it with limit to fetch the next page. |
generalprogrammingdesignmarketingsalescustomer-supportwritingdata-sciencedevopsproduct-managementhuman-resourcesfinancelegaldentalhealthcarecurriculum-developmenteducationai-machine-learningai-trainingcybersecurityfinancial-crimesehsquality-assurancegraphic-designmedical-recordscomplianceenvironmental-safetycyber-securityfitness-wellnessaccountingpersonal-training03 / Response reference
Each v1 response contains a data array of jobs, a pagination object, and meta with attribution and documentation links.
| Job fields | What to expect |
|---|---|
id, title | A job identifier and the listing title. |
url, apply_url | Both point to the job’s RemoteJobs.org page. Use these links to let readers view the listing and apply. |
company, category | Company name, logo_url, website, and profile url; category name and slug. Logo and website may be null. |
location | The listing’s location text, or null. Remote roles can still have country or region restrictions. |
location_normalization | Versioned geography with ISO country and subdivision codes, allowed and excluded areas, IANA timezone identifiers, original raw wording, and known, partial, unknown, or conflicting status. Bare Remote does not establish worldwide eligibility; working hours and legal eligibility require separate evidence. |
salary_min, salary_max, salary_text | Native pay bounds and formatted pay text. Each bound may independently be null. Amounts are not annualized or converted between currencies. |
salary_currency, salary_period | Recorded currency code and pay period: hour, day, week, month, or year. Either may be null. Compare amounts only when both currency and period are known and match. |
salary_source_text | Retained source pay wording, or null. Missing currency or period stays unknown. |
type, employment_types | type is a summary display label or null when unavailable. employment_types is the complete set of Google JobPosting classifications, or null; full-time and contractor can coexist. Type filters match this set. |
employer_job_id, direct_apply | Employer-issued identifier and verified direct-application classification, or null. A working application URL alone does not establish direct_apply. |
description | Sanitized HTML preserving supported description content, with a RemoteJobs.org application link appended. Apply your own HTML policy when displaying it in your application. |
posted_at | The posting timestamp, returned as an ISO 8601 string. |
is_translated, original_language | Whether the listing was translated, and its original language when recorded. The language may be null. |
{
"data": [
{
"id": "a1b2c3d4-5678-4abc-9012-3456789abcde",
"title": "Senior Frontend Engineer",
"url": "https://remotejobs.org/remote-jobs/senior-frontend-engineer-acme",
"apply_url": "https://remotejobs.org/remote-jobs/senior-frontend-engineer-acme",
"company": {
"name": "Acme Corp",
"logo_url": null,
"website": "https://example.com",
"url": "https://remotejobs.org/companies/acme-corp"
},
"category": {
"name": "Programming",
"slug": "programming"
},
"location": "Remote (Worldwide)",
"salary_min": 120000,
"location_normalization": {
"version": "job-location/1",
"reference_version": "iso-3166@4.4.0",
"raw": "Remote (Worldwide)",
"input": {},
"status": "known",
"scope": "worldwide",
"work_arrangement": "remote",
"allowed_countries": [],
"allowed_subdivisions": [],
"excluded_countries": [],
"excluded_subdivisions": [],
"timezones": [],
"regions": [],
"unresolved": []
},
"salary_max": 160000,
"salary_text": "USD 120,000–160,000/year",
"salary_source_text": "$120,000–$160,000 USD per year",
"salary_currency": "USD",
"salary_period": "year",
"type": "Full-time",
"employment_types": [
"FULL_TIME"
],
"employer_job_id": null,
"direct_apply": null,
"description": "<p>Help us build our next product.</p>\n<p>Apply directly on <a href=\"https://remotejobs.org\">RemoteJobs.org</a>: https://remotejobs.org/remote-jobs/senior-frontend-engineer-acme</p>",
"posted_at": "2026-10-01T09:00:00Z",
"is_translated": false,
"original_language": null
}
],
"pagination": {
"total": 42,
"limit": 1,
"offset": 0,
"has_more": true
},
"meta": {
"powered_by": "RemoteJobs.org",
"url": "https://remotejobs.org",
"docs": "https://remotejobs.org/developers/api"
}
}04 / Pagination
Start with offset=0. Increase it by your page size for each request, keeping the same filters.
?limit=20&offset=0?limit=20&offset=20?limit=20&offset=40Know when to stop. Check pagination.has_more before continuing, and stop if data is empty. pagination.total counts matching indexed listings in that request. If a count cannot be retrieved, the request returns an error. Listings can change between requests; pagination isn’t a fixed snapshot.
05 / Structured discovery
Use a structured text-and-filter request when you want compact job summaries and cursor continuation. The existing v1 GET endpoint remains available for exact indexed totals and full job responses.
https://remotejobs.org/api/v2/jobs/discovercurl --fail 'https://remotejobs.org/api/v2/jobs/discover' \
-H 'Content-Type: application/json' \
--data '{"search":{"text":"react","filters":{"category":"programming"}},"take":10}'Send search with optional text and filters, plus take from 1 to 20 (default 10). Text accepts up to 500 characters. Filters include category, employment type, hiring country and salary criteria. Results contain jobs, next_cursor, previous_cursor, coverage, ranking metadata, and total: { kind: "unknown" }.
Continue the same search. Pass next_cursor with the same search and take; do not add an offset. Cursors expire after ten minutes. Restart without a cursor after 409 (results changed) or 410 (expired). A null next_cursor ends the retained result window, not the whole matching catalog.
Discovery payloads are bounded to 32 KiB and may return fewer summaries than requested. Follow the listing URL for the full posting, or use MCP’s get_job for selected Markdown sections. v1 and v2 requests share the API limit of 200 requests per hour per IP address; MCP has a separate request limit.
06 / Limits & caching
Keep usage below 200 requests per hour per IP address. Rate limiting is best-effort; this is not a guaranteed quota. API v1 and v2 share this limit; MCP requests are limited separately. v1 returns up to 50 jobs, while structured discovery returns up to 20 compact summaries per request. Cache results in your application and avoid polling on every page view.
New requests read current indexed listings. v1 pages can change between requests. Structured discovery retains a result window for up to ten minutes and validates returned jobs on continuation. Cache a response in your application when repeated requests do not need fresh results.
| Status | Next step |
|---|---|
200 OK | For v1, read data and pagination. For discovery, read jobs and its continuation cursor. An empty page is not an API failure. |
400 Invalid request | Send whole numbers for limit and offset. |
409, 410 Discovery changed or expired | Restart structured discovery without a cursor, keeping your intended search criteria. |
429 Rate limited | Wait for the number of seconds in Retry-After before trying again. |
500, 503 Server unavailable | The API couldn’t fetch jobs. Retry later rather than treating the failure as an empty result. |
Rate-limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (a Unix timestamp in seconds).
07 / Attribution
If you display listings from the API, please include a visible link back to RemoteJobs.org and keep the job’s application link intact. Here’s a simple attribution you can use.
<a href="https://remotejobs.org">
Powered by RemoteJobs.org
</a>Use of the API and third-party content is covered by our terms of service.
From an idea to an integration
Start with a request. Get in touch if you need help with a larger integration.