# Sap Successfactors

> SAP SuccessFactors HXM development and integration skill. Use when working with SF OData APIs (Employee Central, Recruiting, Performance), creating MDF custom objects, configuring Intelligent Services events, implementing RBP permissions, or building BTP extensions for SuccessFactors. If the user mentions SuccessFactors, Employee Central, SF API, MDF object, or HR integration with SAP, use this skill.

- Skill: `efeumutaslan/sap-successfactors` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add efeumutaslan/sap-successfactors`
- Raw SKILL.md: https://api.skillmd.com/api/skills/efeumutaslan/sap-successfactors/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: efeumutaslan (https://skillmd.com/u/efeumutaslan)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/efeumutaslan/sap-successfactors

---


# SAP SuccessFactors HXM Development

## Related Skills
- `sap-security-authorization` — XSUAA/IAS for BTP-side extensions
- `sap-s4hana-extensibility` — Hybrid HR/Finance integration scenarios
- `sap-integration-suite-advanced` — Pre-built SF iFlows and API Management
- `sap-event-mesh` — SF Intelligent Services events to BTP Event Mesh
- `sap-cap-advanced` — CAP-based BTP extensions consuming SF APIs

## Quick Start

**Choose your development approach:**

| Scenario | Approach | API |
|----------|----------|-----|
| Read/write employee data | OData V2 API | `/odata/v2/` endpoints |
| Custom business objects | MDF (Metadata Framework) | MDF OData API |
| Event-driven extension | Intelligent Services | Event triggers → BTP |
| Analytics / reporting | People Analytics OData | `$metadata` reporting |
| UI extension | Extension Center | Custom UI on SF pages |
| Integration | SAP Integration Suite | Pre-built iFlows |

**Minimal API call — Get employee by ID:**

```http
GET https://<api-server>/odata/v2/User('EMPL001')
  ?$select=userId,firstName,lastName,email,department
  &$format=json
Authorization: Bearer <oauth_token>
```

## Core Concepts

### API Architecture
- **OData V2**: Primary API protocol for all SuccessFactors entities
- **Entity sets**: Map to business objects (User, EmpJob, EmpEmployment, PerPersonal, etc.)
- **Compound Employee API**: Single request for employee + all related entities
- **Associations**: Navigate between entities (`User('ID')/directReports`)
- **Effective dating**: Most HR entities have `startDate`/`endDate` for temporal data

### Metadata Framework (MDF)
- **Generic Objects (GOs)**: Custom business objects defined via MDF
- **Rules engine**: Business rules attached to MDF objects (onInit, onSave, onChange)
- **Picklists**: Reusable value lists for dropdowns
- **Association types**: 1:1, 1:N, configurable navigation
- **MDF OData**: Auto-generated OData endpoints for custom MDF objects

### Permission Model (RBP)
- **Role-Based Permissions (RBP)**: Foundation of SF security
- **Permission roles**: Group of permission grants assigned to users
- **Target population**: Which employees a role can access (granting rules)
- **Permission groups**: Logical grouping of entities and fields
- **Field-level permissions**: Control read/write/hidden per field per role

### Integration Patterns
| Pattern | Tool | When |
|---------|------|------|
| Real-time sync | SAP Integration Suite iFlows | Employee master → S/4HANA |
| Event-driven | Intelligent Services → BTP | React to HR events |
| Batch extract | OData `$filter` with paging | Nightly data sync |
| UI mashup | Extension Center / BTP HTML5 | Embed custom UI in SF |

## Common Patterns

### Pattern 1: Compound Employee API (Efficient Bulk Read)

```http
GET /odata/v2/CompoundEmployee
  ?$filter=lastModifiedDateTime gt datetime'2026-03-01T00:00:00'
  &$select=person/personIdExternal,
           personalInfo/firstName,personalInfo/lastName,
           jobInfo/company,jobInfo/department,jobInfo/jobTitle,
           employmentInfo/startDate
  &$format=json
  &$top=100
  &$skiptoken=<token_from_previous_response>
```

### Pattern 2: Create Custom MDF Object Record

```http
POST /odata/v2/upsert
Content-Type: application/json

{
  "__metadata": {
    "uri": "cust_Equipment('NEW001')"
  },
  "externalCode": "NEW001",
  "cust_name": "MacBook Pro 16",
  "cust_assignedTo": "EMPL001",
  "cust_status": "ASSIGNED",
  "effectiveStartDate": "/Date(1711929600000)/"
}
```

### Pattern 3: Event-Driven Extension (Intelligent Services)

```javascript
// BTP Cloud Foundry / Kyma — handle SF event
const express = require('express');
const app = express();

app.post('/sf-events', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'HIRE':
      console.log(`New hire: ${event.userId}, start: ${event.startDate}`);
      // Trigger provisioning: AD account, equipment, onboarding tasks
      provisionNewHire(event.userId);
      break;
    case 'TERMINATION':
      console.log(`Termination: ${event.userId}, last day: ${event.endDate}`);
      // Trigger de-provisioning
      deprovisionEmployee(event.userId);
      break;
  }

  res.status(200).json({ status: 'processed' });
});

app.listen(process.env.PORT || 8080);
```

### Pattern 4: OData Batch Request

```http
POST /odata/v2/$batch HTTP/1.1
Content-Type: multipart/mixed; boundary=batch_001

--batch_001
Content-Type: application/http
Content-Transfer-Encoding: binary

GET User?$filter=department eq 'IT'&$select=userId,firstName,lastName&$top=50 HTTP/1.1
Accept: application/json

--batch_001
Content-Type: application/http
Content-Transfer-Encoding: binary

GET EmpJob?$filter=company eq '1010' and startDate ge datetime'2026-01-01T00:00:00'&$top=50 HTTP/1.1
Accept: application/json

--batch_001--
```

### Pattern 5: OAuth2 SAML Bearer Token Flow

```javascript
const axios = require('axios');
const { SignedXml } = require('xml-crypto');

async function getSFToken(userId) {
  // 1. Generate SAML assertion (signed with X.509 cert)
  const samlAssertion = generateSAMLAssertion(userId);

  // 2. Exchange SAML assertion for OAuth2 token
  const tokenResponse = await axios.post(
    'https://<api-server>/oauth/token',
    new URLSearchParams({
      grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer',
      assertion: Buffer.from(samlAssertion).toString('base64'),
      client_id: '<api_key>',
      company_id: '<company_id>'
    }),
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  );

  return tokenResponse.data.access_token;
}
```

### Pattern 6: People Analytics OData Report

```http
GET /odata/v2/cust_headcountReport
  ?$filter=asOfDate eq datetime'2026-03-24T00:00:00'
  &$select=department,headcount,fte,avgTenure
  &$orderby=department asc
  &$format=json
```

## Error Catalog

| HTTP Status | Error | Root Cause | Fix |
|-------------|-------|------------|-----|
| `401` | `Invalid OAuth token` | Token expired or wrong API server | Refresh token; verify token URL matches API server region |
| `403` | `Insufficient permissions` | RBP role missing for entity/field | Check Admin Center → Manage Permission Roles; add entity permissions |
| `400` | `Invalid effective date` | Date format wrong or future-dated insert blocked | Use `/Date(epoch)/` format; check date restrictions on entity |
| `404` | `Entity not found` | Wrong entity name or entity not enabled | Check `$metadata`; some entities need activation in Provisioning |
| `429` | `Rate limit exceeded` | Too many API calls per minute | Implement exponential backoff; use `$batch` for bulk operations |
| `500` | `Business rule validation failed` | MDF rule rejected the data | Check Manage Business Rules for the object; review rule conditions |

## Performance Tips

1. **Use `$select`** — Always specify needed fields; SF returns ALL fields by default (very slow)
2. **Compound Employee API** — One call vs. 5-10 separate entity calls per employee
3. **`$batch` requests** — Group up to 100 operations in one HTTP call; reduces round-trips
4. **Paging with `$skiptoken`** — Never use `$skip` for large datasets; use server-driven paging
5. **`lastModifiedDateTime` filter** — Delta sync instead of full extract
6. **Cache `$metadata`** — Metadata response is large (>1 MB); cache it, refresh daily
7. **Avoid deep expansions** — `$expand` with 3+ levels causes timeouts; use separate queries
8. **Time zone awareness** — All dates in UTC; convert at display layer, not in API queries

## Gotchas

- **Effective dating**: Every update to EmpJob, EmpEmployment, etc. requires `startDate`; omitting it creates records effective "today" which may conflict with existing records
- **Picklist values**: Use `picklistId` + `optionId`, NOT display text — display text is locale-dependent
- **API server vs. data center**: Token endpoint and API base URL may be different hostnames
- **SAML assertion clock skew**: Assertions must have `NotBefore` / `NotOnOrAfter` within 5 min of server time
- **MDF field limits**: Custom MDF objects max 150 fields; plan field usage carefully
- **Integration Center vs. Suite**: Integration Center (within SF) for simple scenarios; SAP Integration Suite for complex multi-system flows

## Advanced Patterns

### Extension Center — Custom UI Injection

```javascript
// SF Extension Center: inject custom UI into SuccessFactors pages
// Hosted on BTP HTML5 Application Repository
// Registered via Admin Center → Extension Center

// manifest.json (Fiori-style)
{
  "sap.app": {
    "id": "com.company.sf.custom-onboarding",
    "type": "application",
    "applicationVersion": { "version": "1.0.0" }
  },
  "sap.sf.extension": {
    "targetPage": "EmployeeProfile",
    "position": "belowHeader",
    "label": "Custom Onboarding Checklist"
  }
}
```

### Employee Central → S/4HANA Replication

```
SF Employee Central               SAP S/4HANA
     │                                 │
     ├─ Employee master data ─────────►│ Business Partner (BP)
     │  (HCM replication)              │
     ├─ Org structure ────────────────►│ Org Management
     │                                 │
     ├─ Cost center assignment ───────►│ CO cost centers
     │                                 │
     └─ Compensation data ────────────►│ Payroll (optional)
```

**Replication setup:**
1. Enable API Center in SF (Admin Center → Company Settings)
2. Configure Integration Center for employee replication
3. Map SF fields to S/4HANA BP fields
4. Set up delta sync (lastModifiedDateTime filter)

### MDF Business Rules Engine

```
Rule Type: onChange
Object: cust_LeaveRequest
Trigger Field: cust_leaveType

IF cust_leaveType == "ANNUAL"
  THEN SET cust_requiresApproval = TRUE
  AND SET cust_maxDays = 30

IF cust_leaveType == "SICK"
  AND cust_days > 3
  THEN SET cust_requiresMedicalCert = TRUE

IF cust_startDate < TODAY()
  THEN RAISE ERROR "Leave start date cannot be in the past"
```

## Bundled Resources

| File | When to Read |
|------|-------------|
| `references/sf-api-reference.md` | Full SF API entity reference with query patterns |

## Source Documentation

- [SAP SuccessFactors API Reference](https://help.sap.com/docs/SAP_SUCCESSFACTORS_PLATFORM/d599f15995d348a1b45ba5603e2aba9b)
- [SF Extension Center Guide](https://help.sap.com/docs/SAP_SUCCESSFACTORS_PLATFORM/f8796a3df8204c57b5f7f7c0776cde72)
- [SF OData API Business Rules](https://help.sap.com/docs/SAP_SUCCESSFACTORS_PLATFORM)

