City feed
The Rocky Mountain tech hub in one stable API. Denver and Boulder roles from Greenhouse, Lever, Ashby, and Workable — a growing market that most national feeds underweight. The region's outdoor lifestyle draw has pulled in a steady stream of relocating engineers, which shows up as sustained inbound hiring rather than a single-industry boom.
Denver's tech market is growing fast but gets treated as secondary in most job data feeds. Colorado-specific boards end up with national data that's mostly irrelevant or a thin local slice that misses half the market.
We maintain a dedicated Colorado feed covering Denver and Boulder with precise city normalization — built for Mountain West boards, not bolted onto a national query. Aerospace and space-tech listings, a Colorado specialty tied to the state's defense and aerospace contractor base, are captured alongside the more visible SaaS and startup roles.
When you are ready for every filter, validation rule, and response field, use the Jobs API reference.
1,577,168
Total Jobs Indexed
+10,320
Added Past 24h
+852,605
Added Past 30 Days
24,882
Employers
Same query as the playground, as cURL. Use your real key on the server only.
curl -X GET "https://api.cleanjobdata.com/jobs?city_id=115252&max_age=30d" \ -H "Authorization: Bearer YOUR_API_KEY"
Sign up for CleanJobData, open the dashboard, and create or copy your API key. Send it as Authorization: Bearer <token> on every request (server-side only in production—never expose keys in mobile apps or public repos).
Start from GET /jobs?city_id=115252 for Denver, then add &title=... or &remote=true as needed — e.g. GET /jobs?city_id=115252&remote=true.
Use a modest limit while prototyping, default to sort_by=published for recency, then follow pagination.next_page for large imports. Back off with exponential retry if you hit rate limits.
List responses default to a lightweight field set with no description — add extra_fields=description when a view needs the full HTML body (e.g. GET /jobs?extra_fields=description), or pass fields=id,title,company,location,salary_min,salary_max to replace the default set entirely with just what a card renders. Detail requests (GET /jobs/:id) always include description, no extra param needed.
Yes—that is the intended use case. The free Trial tier (250 list + 500 detail requests/mo, no card required) is enough to prototype and verify data quality; Starter ($97/mo, 100,000 requests/mo) and Pro ($297/mo, 500,000 requests/mo) cover most production job boards. Keep your API key server-side, cache responses where it makes sense, and follow the cursor pagination contract for large imports.
Combine the location filters already applied on this page with title (GET /jobs?title=React+engineer), remote=true or the finer remote_type=fully_remote|remote_country|remote_region|hybrid, experience_level=SE,EX for seniority, or salary=100000,180000 for a compensation range. Every combination is documented with validation rules on the Jobs API reference (/docs/api/jobs).
Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers, so you can watch your usage and slow down before hitting a 429 rather than reacting to one. The per-second limit resets within a second or two if you do hit it — a short wait and retry is enough. A separate, unrelated 429 fires if you exhaust your plan's monthly request quota; that one won't clear by waiting, so check the error message text to tell the two apart.
We normalize employers, locations, salary text, and remote flags into one schema, refresh listings continuously, and expose stable HTTP filters. You spend time on product and UX instead of repairing scrapers every time a site changes markup.
We refresh listings continuously from our sources. Use sort_by=published (the default) for newest-first ordering, and for incremental syncs use created_max_age=1d (or 6h, 7d — a rolling window on ingestion time) rather than published_after, since a listing can finish processing after its original publish date and published_after alone can miss it.
Not by default — list responses use a lightweight field set to keep list pages and mobile clients fast. Add extra_fields=description to a list request (e.g. GET /jobs?extra_fields=description) to include it, or use fields=id,title,description,... to request an explicit set. The single-job detail endpoint (GET /jobs/:id) always includes the full description with no extra param needed.