SAP SuccessFactors Jobs API
Read job postings from public SAP SuccessFactors career sites as structured JSON, with no API key and no SAP login. A SuccessFactors career site such as jobs.sap.com publishes its whole live job list as one public feed, and this API reads that feed, so a single request returns every open role on the site: requisition ID, title, employer, job function, location, country code and expiration date. Descriptions come back as Markdown by default, or as the original HTML or plain text. The feed has no posted date, so an optional add-on opens each job's own page for the posted date, department, facility, shift type and travel requirement. Title, job function, location, remote and active-only filters run before billing, so a filtered job costs nothing.
Input parameters
| PARAMETER | TYPE | REQ | DEFAULT | DESCRIPTION |
|---|---|---|---|---|
| companies | string[] | no | — | Career-site hosts (jobs.sap.com), full career-site URLs, single job URLs (/job/ |
| startUrls | string[] | no | — | The same career-site and single-job URLs in URL-list form, merged with companies. |
| outputMode | enum | no | jobs | jobs (full job records), urlsOnly (the job index without descriptions, the cheapest way to list everything) or tenantsOnly (one row per career site with a live open-jobs count). |
| discoveryQuery | string | no | — | Case-insensitive text matched against company names and tenant keys in the bundled directory. Scopes tenantsOnly runs and empty-input sweeps. |
| verifyTenants | boolean | no | true | tenantsOnly mode: probe each career site's live feed first and add a current job count. Dead sites are skipped and never billed. |
| titleKeywords | string[] | no | — | Keep only jobs whose title contains any of these, for example engineer or sales. Case-insensitive, and every filter runs before billing. |
| jobFunctions | string[] | no | — | Keep only jobs whose job function contains any of these, for example Development, Sales or Administration. |
| locationKeywords | string[] | no | — | Keep only jobs whose location string contains any of these, for example Berlin, Bangalore or Remote. |
| activeOnly | boolean | no | true | Drop postings whose expiration date has already passed. |
| remoteOnly | boolean | no | false | Keep only jobs whose title or location reads as remote: remote, anywhere, work from home or virtual. |
| includeDescriptionMarkdown | boolean | no | true | Add descriptionMarkdown, the posting converted to Markdown. A paid add-on billed per job row that carries it; turn it off for metadata-only rows. |
| includeDescriptionHtml | boolean | no | false | Add descriptionHtml, the original posting markup. A paid add-on billed per row that carries it. |
| includeDescriptionText | boolean | no | false | Add descriptionText, a clean plain-text rendering. A paid add-on billed per row that carries it. |
| includeDetailFields | boolean | no | false | Open each job's own page for datePosted, department, facility, shiftType, travel and customFields. One extra request per job, so large runs are slower. A paid add-on billed per row that carries the data. |
| report | enum | no | none | none, markdown or html. Writes a digest of the run's jobs, grouped by company, to the key-value store under REPORT. One flat charge, capped at 5,000 rows. |
| maxTenants | integer | no | 25 | Cap on career sites processed in a directory sweep or a tenantsOnly run, 1 to 50,000. |
| maxJobsPerTenant | integer | no | 0 | Cap on job rows per career site after filtering. 0 means no per-site cap. |
| maxJobs | integer | no | 100 | Hard ceiling on billable rows across the whole run, all career sites combined. The main cost control; 0 means unlimited. — drives your bill |
| maxConcurrency | integer | no | 5 | Parallel detail-page fetches when the detail add-on is on, and parallel probes in discovery, 1 to 10. Reading a career site's feed is always one request. |
Output schema
| FIELD | TYPE | DESCRIPTION | NULLABLE |
|---|---|---|---|
| resultType | string | What this row is: job (a full job record), url (a job index row), tenant (a discovered career site) or error (a career site or job that could not be read, never billed). | no |
| requisitionId | string | The career site's public requisition ID for the posting. | yes |
| title | string | The posting title. | yes |
| companyName | string | The hiring company: the feed's employer field, else the directory name, else the career-site host. | yes |
| employer | string | The employer name exactly as the feed publishes it. | yes |
| tenant | string | The career-site host this row came from, for example jobs.sap.com. | yes |
| careerSiteUrl | string | The career site's home URL. | yes |
| url | string | Canonical public URL of the posting. Dedupe key. | yes |
| applyUrl | string | The application page for the posting. | yes |
| jobFunction | string | The job function as the feed publishes it. | yes |
| location | string | The location string, usually city, two-letter country code and postcode. | yes |
| countryCode | string | Two-letter country code parsed from the location string, when present. | yes |
| validThrough | string | The posting's expiration date (ISO date). The field behind activeOnly. | yes |
| isRemote | boolean | Remote flag inferred from words in the title and location. Null when both are empty. | yes |
| datePosted | string | The date the posting went live (ISO date). Detail add-on only; the feed does not carry it. | yes |
| department | string | Department from the job's own page. Detail add-on only. | yes |
| facility | string | Facility identifier from the job's own page. Detail add-on only. | yes |
| shiftType | string | Shift or work-time type from the job's own page. Detail add-on only. | yes |
| travel | string | Travel requirement from the job's own page, for example 0 - 10%. Detail add-on only. | yes |
| customFields | object | Employer-defined fields from the job's own page. Detail add-on only. | yes |
| salaryDerived | object | Salary range parsed from the description text when it states one: min, max, currency, period and source. | yes |
| salaryMin | number | Lower bound of the parsed salary range, flattened for tables and CSV. | yes |
| salaryMax | number | Upper bound of the parsed salary range. | yes |
| salaryCurrency | string | Currency code of the parsed salary range. | yes |
| salaryPeriod | string | Pay period of the parsed range: year, month, week, day or hour. | yes |
| descriptionMarkdown | string | The posting converted to Markdown. Present when the Markdown add-on is on. | yes |
| descriptionHtml | string | The original posting markup from the feed. Present when the HTML add-on is on. | yes |
| descriptionText | string | A plain-text rendering of the posting. Present when the text add-on is on. | yes |
| flavor | string | The SuccessFactors site variant the row came from: rmk, for Recruiting Marketing career sites. | yes |
| source | string | Always successfactors, for merging with other ATS datasets. | yes |
| sourceType | string | Always ats. | yes |
| sourceUrl | string | The input entry that produced the row, when it was a URL. | yes |
| jobCount | integer | Tenant rows: live jobs in the career site's feed at verification time. | yes |
| live | boolean | Tenant rows: whether the feed answered the live probe. Null when verification was off. | yes |
| verifiedAt | string | Tenant rows: when the live probe ran (ISO 8601). | yes |
| errorCode | string | Error rows: invalid_url, tenant_not_found, job_not_found, http_error, invalid_input or run_failed. | yes |
| errorMessage | string | Error rows: a readable explanation, safe to display. | yes |
| didYouMean | string[] | Error rows: the closest known tenant keys when a career site was not found. | yes |
| scrapedAt | string | When the row was produced (ISO 8601, UTC). | no |
Worked examples
{"companies": ["jobs.sap.com"], "maxJobs": 25}
{"companies": ["jobs.sap.com"], "titleKeywords": ["engineer", "developer"], "locationKeywords": ["Walldorf", "Berlin"], "maxJobs": 100}
{"companies": ["jobs.sap.com"], "outputMode": "urlsOnly", "maxJobs": 0}
{"companies": ["jobs.sap.com"], "includeDetailFields": true, "includeDescriptionMarkdown": false, "maxJobs": 20}
{"outputMode": "tenantsOnly", "companies": ["jobs.sap.com"]}
Coverage
Code
Read a career site in one call
curl -X POST "https://api.apify.com/v2/acts/johnvc~sap-successfactors-jobs-api/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"companies": ["jobs.sap.com"], "titleKeywords": ["engineer"], "maxJobs": 50}'
Python
from apify_client import ApifyClient
client = ApifyClient("APIFY_TOKEN")
run = client.actor("johnvc/sap-successfactors-jobs-api").call(
run_input={"companies": ["jobs.sap.com"], "titleKeywords": ["engineer"], "maxJobs": 50}
)
for row in client.dataset(run.default_dataset_id).iterate_items():
if row.get("resultType") == "error":
print("error:", row.get("errorCode"), row.get("errorMessage"))
else:
print(row.get("title"), "|", row.get("location"), "|", row.get("validThrough"), "|", row.get("url"))
MCP
claude mcp add --transport http successfactors-jobs \ "https://mcp.apify.com/?tools=actors,docs,johnvc/sap-successfactors-jobs-api"
Sample job row (synthetic)
{
"resultType": "job",
"requisitionId": "1400000001",
"title": "Senior Data Engineer",
"companyName": "Example Corp",
"employer": "Example Corp",
"tenant": "jobs.example.com",
"careerSiteUrl": "https://jobs.example.com",
"url": "https://jobs.example.com/job/Berlin-Senior-Data-Engineer/1400000001/",
"applyUrl": "https://jobs.example.com/job/Berlin-Senior-Data-Engineer/1400000001/",
"jobFunction": "Development",
"location": "Berlin, DE, 10115",
"countryCode": "DE",
"validThrough": "2026-11-30",
"isRemote": false,
"salaryMin": null,
"salaryMax": null,
"descriptionMarkdown": "**About the role**\n\nExample Corp is hiring a senior data engineer to build its reporting pipelines.",
"flavor": "rmk",
"source": "successfactors",
"sourceType": "ats",
"scrapedAt": "2026-10-09T14:00:00Z"
}
What people use it for
- Backfilling a job board from enterprise ATS sites
- Sales prospecting on enterprise hiring activity
- Feeding an AI recruiting agent Markdown job descriptions
- Tracking new requisitions on a SuccessFactors site by diffing IDs between runs
- Breaking down an employer's open roles by department, facility and shift type
- Indexing every open requisition on a career site without descriptions
More sources for Hiring signals and talent intelligence, Grounding AI agents and MCP tools →