{"openapi":"3.1.0","info":{"title":"CleanJobData API","version":"1.0.0","description":"Job listings collected from employer ATS platforms and company career sites, normalized into one JSON schema. Docs: https://cleanjobdata.com/docs. Get a key: https://cleanjobdata.com/signup.","contact":{"name":"CleanJobData","url":"https://cleanjobdata.com/support"},"termsOfService":"https://cleanjobdata.com/terms"},"externalDocs":{"url":"https://cleanjobdata.com/docs","description":"Full documentation"},"servers":[{"url":"https://api.cleanjobdata.com"}],"security":[{"bearerAuth":[]}],"paths":{"/jobs":{"get":{"operationId":"listJobs","summary":"Search and list jobs","description":"Returns a page of jobs matching the filters, newest published first. Paginate by passing pagination.next_page back as cursor.","externalDocs":{"url":"https://cleanjobdata.com/docs/api/jobs"},"parameters":[{"name":"title","in":"query","required":false,"description":"Search by job title or keywords. Supports full-text search.","schema":{"type":"string"},"example":"software engineer"},{"name":"search","in":"query","required":false,"description":"Alias of title (same behavior).","schema":{"type":"string"},"example":"software engineer"},{"name":"sort_by","in":"query","required":false,"description":"Sort order. Values: published (default), relevance (requires title).","schema":{"type":"string"},"example":"relevance"},{"name":"city_id","in":"query","required":false,"description":"Filter by specific city ID. Comma-separated.","schema":{"type":"number"},"example":"5391959"},{"name":"state_id","in":"query","required":false,"description":"Filter by specific state ID. Comma-separated.","schema":{"type":"number"},"example":"5332921"},{"name":"country_id","in":"query","required":false,"description":"Filter by specific country ID. Comma-separated.","schema":{"type":"number"},"example":"233"},{"name":"location","in":"query","required":false,"description":"When no city_id, state_id, or country_id are provided: comma-separated ISO 3166-1 alpha-2 country codes (e.g. US,GB,DE). Invalid tokens are skipped.","schema":{"type":"string"},"example":"US,CA"},{"name":"remote","in":"query","required":false,"description":"Set to true for remote-only jobs (filters on has_remote). Requires the exact string true — 1 or yes are not accepted here, unlike some other boolean flags.","schema":{"type":"boolean"},"example":"true"},{"name":"remote_type","in":"query","required":false,"description":"Narrow remote jobs further. Values: fully_remote, remote_country (restricted to a country), remote_region (restricted to a region), hybrid.","schema":{"type":"string"},"example":"fully_remote"},{"name":"company_name","in":"query","required":false,"description":"Filter by company name (substring match).","schema":{"type":"string"},"example":"Stripe"},{"name":"employer_id","in":"query","required":false,"description":"Filter by one or more company IDs (the id returned by the Companies API). Comma-separated, up to 100. Not something you look up ahead of time — most job responses include employer_id at the top level (older rows without a resolved ATS employer can have it null), so capture it off any job that has one and reuse it.","schema":{"type":"string"},"example":"a1B2c3, x9Y8z7"},{"name":"company_website_url","in":"query","required":false,"description":"Filter by the company's own website domain (not the job board's hosting domain). Matches by registrable domain, so a bare domain or full URL both work. This is the reliable way to scope to a specific employer's real site — see domain below for a narrower, application-URL-derived alternative.","schema":{"type":"string"},"example":"stripe.com"},{"name":"domain","in":"query","required":false,"description":"Exact match against each job's application_url domain — not the same as company_website_url above. For jobs hosted on an ATS (Applicant Tracking System — the platform an employer uses to post and manage listings, e.g. Greenhouse, Lever), this is often the ATS's own hosting domain (e.g. boards.greenhouse.io) rather than the employer's real site, so it's a narrower tool: useful when you specifically know the domain a job's application link resolves to, not a general company-scoping filter.","schema":{"type":"string"},"example":"acme.com"},{"name":"fields","in":"query","required":false,"description":"Comma-separated allowlist: response includes only these columns (must be from the allowed set). Replaces the default summary projection.","schema":{"type":"string"},"example":"id,title,company,published"},{"name":"include_fields","in":"query","required":false,"description":"Legacy alias of fields — same behavior. Prefer fields for new integrations.","schema":{"type":"string"},"example":"id,title,company"},{"name":"extra_fields","in":"query","required":false,"description":"Comma-separated columns to add on top of the default summary (e.g. description). Silently ignored if fields or include_fields is also present in the same request — those take priority and extra_fields never gets applied on top.","schema":{"type":"string"},"example":"description"},{"name":"exclude_fields","in":"query","required":false,"description":"Comma-separated columns to remove from the resolved field set (applied after extra_fields). Same caveat as extra_fields: silently ignored whenever fields or include_fields is also set.","schema":{"type":"string"},"example":"description,company"},{"name":"count","in":"query","required":false,"description":"Set to true to include pagination.count: the total number of jobs matching your filters (not just the current page). Costs an extra query — omit unless you need it.","schema":{"type":"boolean"},"example":"true"},{"name":"salary","in":"query","required":false,"description":"Filter by salary range. Format: min,max (e.g. 100000,150000) — or just min alone (e.g. 100000) for a lower-bound-only filter with no upper cap.","schema":{"type":"string"},"example":"100000,150000"},{"name":"min_salary","in":"query","required":false,"description":"Legacy lower-bound-only alias. Prefer salary=min for new integrations.","schema":{"type":"number"},"example":"100000"},{"name":"require_salary","in":"query","required":false,"description":"By default, salary/min_salary filters also include jobs with no disclosed salary. Set true to only return jobs with a verified salary meeting your minimum.","schema":{"type":"boolean"},"example":"true"},{"name":"experience_level","in":"query","required":false,"description":"Values: EN (Entry), MI (Mid), SE (Senior), EX (Executive). Comma-separated.","schema":{"type":"string"},"example":"SE,EX"},{"name":"employment_type","in":"query","required":false,"description":"Values: FULL_TIME, PART_TIME, CONTRACT, INTERN, TEMPORARY, FREELANCE, APPRENTICESHIP, VOLUNTEER, PER_DIEM, OTHER. Comma-separated.","schema":{"type":"string"},"example":"FULL_TIME,CONTRACT"},{"name":"published_after","in":"query","required":false,"description":"ISO 8601 timestamp: only jobs published at or after this instant. When set, max_age is not applied on the same request.","schema":{"type":"string"},"example":"2024-05-01T00:00:00.000Z"},{"name":"max_age","in":"query","required":false,"description":"Rolling window on published date: positive integer with optional unit h (hours), d (days), w (weeks). A bare number is treated as days (e.g. 7 equals 7d). Omit if using published_after.","schema":{"type":"string"},"example":"24h, 7d, 1w, or 7"},{"name":"created_max_age","in":"query","required":false,"description":"Rolling window on ingestion time instead of published date — same format as max_age. Useful for sync jobs: a listing whose published date is old but only recently finished processing still matches this, which published_after/max_age can miss.","schema":{"type":"string"},"example":"24h, 7d, 1w, or 7"},{"name":"limit","in":"query","required":false,"description":"Results per request. Default 20. Max depends on your plan: 20 on Trial, 50 on Scout and Starter, 100 on Pro and Enterprise. Requests above your tier's max are silently clamped down to it.","schema":{"type":"number"},"example":"50"},{"name":"cursor","in":"query","required":false,"description":"Opaque token from the previous response’s pagination.next_page or pagination.prev_page.","schema":{"type":"string"},"example":"(value from prior response)"},{"name":"next_page","in":"query","required":false,"description":"Same token as pagination.next_page, sent as a query parameter to load the next window.","schema":{"type":"string"},"example":"(value from prior response)"},{"name":"prev_page","in":"query","required":false,"description":"Same token as pagination.prev_page, sent as a query parameter to load the previous window.","schema":{"type":"string"},"example":"(value from prior response)"},{"name":"include_expired","in":"query","required":false,"description":"By default, only is_active jobs are returned. Set to true to also include closed/expired listings — most useful scoped to one employer (with company_website_url or employer_id) for a 'recent roles including closed ones' view.","schema":{"type":"boolean"},"example":"true"}],"responses":{"200":{"description":"A page of jobs.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"next_page":{"type":["string","null"]},"prev_page":{"type":["string","null"]},"count":{"type":"integer","description":"Only with count=true."}}},"meta":{"type":"object","properties":{"query_time_ms":{"type":"integer"},"filters_applied":{"type":"array","items":{"type":"object"}}}}}}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get one job, with its full description","externalDocs":{"url":"https://cleanjobdata.com/docs/api/jobs/by-id"},"parameters":[{"name":"id","in":"path","required":true,"description":"The job's numeric ID.","schema":{"type":"integer"}}],"responses":{"200":{"description":"The job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No job with this ID."},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{id}/apply":{"get":{"operationId":"getApplyLink","summary":"Unlock a job's application URL (Scout plan)","externalDocs":{"url":"https://cleanjobdata.com/docs/api/jobs/apply"},"parameters":[{"name":"id","in":"path","required":true,"description":"The job's numeric ID.","schema":{"type":"integer"}}],"responses":{"200":{"description":"The application URL.","content":{"application/json":{"schema":{"type":"object","properties":{"job_id":{"type":"string"},"application_url":{"type":"string","format":"uri"},"quota_charged":{"type":"boolean"},"unlocks_used":{"type":"integer"},"unlocks_limit":{"type":"integer"}}}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No job with this ID."},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/expired":{"get":{"operationId":"listExpiredJobs","summary":"List IDs of recently expired jobs","description":"Use this to delete closed jobs from your own copy of the data.","externalDocs":{"url":"https://cleanjobdata.com/docs/api/jobs/expired"},"parameters":[{"name":"max_age","in":"query","required":false,"description":"Window on expiry time: integer with optional h, d or w unit. Default 7d.","schema":{"type":"string"},"example":"7d"},{"name":"limit","in":"query","required":false,"description":"Results per request. Default 100, max 1000.","schema":{"type":"number"},"example":"1000"},{"name":"cursor","in":"query","required":false,"description":"pagination.next_cursor from the previous response.","schema":{"type":"string"}}],"responses":{"200":{"description":"Expired job IDs, newest expiry first.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"expired_at":{"type":"string","format":"date-time"}}}},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":["string","null"]}}}}}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/companies":{"get":{"operationId":"searchCompanies","summary":"Search companies by name, website or ID","externalDocs":{"url":"https://cleanjobdata.com/docs/api/companies"},"parameters":[{"name":"q","in":"query","required":false,"description":"Company name (fuzzy match, ranked by relevance).","schema":{"type":"string"},"example":"stripe"},{"name":"website_url","in":"query","required":false,"description":"Company website domain; a bare domain or full URL both work.","schema":{"type":"string"},"example":"stripe.com"},{"name":"employer_id","in":"query","required":false,"description":"One or more company IDs, comma-separated, up to 100.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Results per request. Max and default 20.","schema":{"type":"number"}},{"name":"offset","in":"query","required":false,"description":"Skip N rows. Default 0.","schema":{"type":"number"}}],"responses":{"200":{"description":"Matching companies with at least one active job.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"},"website_url":{"type":["string","null"]},"logo_url":{"type":["string","null"]},"last_job_count":{"type":"integer"},"last_scraped_at":{"type":["string","null"],"format":"date-time"}}}}}}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/geo/suggest":{"get":{"operationId":"suggestLocations","summary":"Look up city, state and country IDs for job filters","externalDocs":{"url":"https://cleanjobdata.com/docs/api/geo/suggest"},"parameters":[{"name":"q","in":"query","required":true,"description":"City, state or country name.","schema":{"type":"string"},"example":"san francisco"},{"name":"kinds","in":"query","required":false,"description":"Comma-separated: city, state, country. Omit for all three.","schema":{"type":"string"},"example":"city"},{"name":"limit","in":"query","required":false,"description":"Max results. Default 10, max 30.","schema":{"type":"number"},"example":"10"}],"responses":{"200":{"description":"Matching locations. Use kind to pick the /jobs filter (city_id, state_id or country_id).","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["city","state","country"]},"name":{"type":"string"},"display_label":{"type":"string"},"city_id":{"type":["integer","null"]},"state_id":{"type":["integer","null"]},"country_id":{"type":["integer","null"]},"country_code":{"type":["string","null"]},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"timezone":{"type":["string","null"]}}}}}}},"400":{"description":"Invalid parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-second rate limit (has X-RateLimit-* headers, retry after a second) or the plan's request quota is used up (no rate-limit headers).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Your CleanJobData API key."}},"schemas":{"Job":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"location":{"type":["string","null"],"description":"Location as display text."},"locations":{"type":["array","null"],"items":{"$ref":"#/components/schemas/Location"}},"company":{"$ref":"#/components/schemas/Company"},"employer_id":{"type":"string","description":"Company ID, usable with employer_id filters and the Companies API."},"published":{"type":"string","format":"date-time","description":"When the employer published the job."},"description":{"type":["string","null"],"description":"Full description. On lists, add extra_fields=description."},"application_url":{"type":["string","null"],"format":"uri","description":"Employer apply link. A cleanjobdata.com redirect on Trial; omitted on Scout (use /jobs/{id}/apply)."},"has_remote":{"type":"boolean"},"remote_type":{"type":["string","null"],"enum":["fully_remote","remote_country","remote_region","hybrid",null]},"is_active":{"type":"boolean"},"expired_at":{"type":["string","null"],"format":"date-time"},"language":{"type":["string","null"]},"employment_type":{"type":["string","null"],"description":"FULL_TIME, PART_TIME, CONTRACT, INTERN, TEMPORARY, ..."},"experience_level":{"type":["string","null"],"enum":["EN","MI","SE","EX",null],"description":"Inferred from the job title, else from a stated years-of-experience requirement."},"experience_levels":{"type":"array","items":{"type":"string","enum":["EN","MI","SE","EX"]}},"salary_min":{"type":["number","null"],"description":"In salary_currency, as published by the employer. No conversion."},"salary_max":{"type":["number","null"]},"salary_currency":{"type":["string","null"],"description":"ISO 4217."},"salary_text":{"type":["string","null"],"description":"Salary as the employer wrote it."}}},"Company":{"type":["object","null"],"description":"Company profile. Optional fields may be null depending on enrichment.","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"logo":{"type":["string","null"],"format":"uri"},"website_url":{"type":["string","null"],"format":"uri"},"linkedin_url":{"type":["string","null"],"format":"uri"},"twitter_url":{"type":["string","null"],"format":"uri"},"github_url":{"type":["string","null"],"format":"uri"},"facebook_url":{"type":["string","null"],"format":"uri"},"instagram_url":{"type":["string","null"],"format":"uri"},"youtube_url":{"type":["string","null"],"format":"uri"},"employee_count":{"type":["string","integer","null"],"description":"Usually a range such as 11-50."},"industry":{"type":["string","null"]},"headquarters":{"type":["string","null"]},"founded":{"type":["integer","null"]},"specialties":{"type":["array","null"],"items":{"type":"string"}},"team":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"title":{"type":["string","null"]},"linkedin_url":{"type":["string","null"]},"photo_url":{"type":["string","null"]}}}}}},"Location":{"type":"object","properties":{"kind":{"type":["string","null"],"description":"Precision of the match, e.g. city_state_country."},"is_primary":{"type":"boolean","description":"True on the first (primary) location."},"city_id":{"type":["integer","null"]},"city_name":{"type":["string","null"]},"state_id":{"type":["integer","null"]},"state_name":{"type":["string","null"]},"state_code":{"type":["string","null"]},"country_id":{"type":["integer","null"]},"country_name":{"type":["string","null"]},"country_code":{"type":["string","null"],"description":"ISO 3166-1 alpha-2."},"lat":{"type":["number","null"]},"lng":{"type":["number","null"]},"timezone":{"type":["string","null"],"description":"IANA timezone."}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}