ICD - HRMS - EPC - Employee Update

Interface Control Document (ICD): HRMS - EPC

---

Document Revision History

Version Status Update Comment By Date
1.0 Draft Initial Draft Retter 05 Feb 2026
1.1 Draft Standardized payload: HRMS sends full record, overwrites member data Retter 10 Feb 2026
1.2 Draft Added companyId (HRMS Business Group ID / BG_ID, required & non-null) and middleName fields; documented company-reassignment use case and the 404/409 BG_ID error responses Retter 23 Jun 2026
1.3 Draft Added optional joiningDate (HRMS JOINING_DATE). Unlike every other field, omitting it or sending null leaves the stored value unchanged rather than clearing it Retter 26 Aug 2026
1.4 Draft EPC-1289: address.address is the HOME address (CUR_RES_ADDRESS, as in the Emirates push ICD); new optional addressOptional is the WORK location. Country compared after parsing. Pushes for members not registered through HRMS are accepted and not applied (skipped) Retter 16 Oct 2026
1.5 Draft EPC-1290: maritalStatus is optional and never rejected (Divorced, Widowed and Separated are stored as single; an unknown value keeps the stored one). birthdate accepts the Oracle timestamp and a date-time with offset and is stored as YYYY-MM-DD. An active status reactivates only a member HRMS deactivated. The email is not written when another member already uses it. A company change moves the dependants too Retter 20 Oct 2026
1.6 Draft EPC-1259: pushes for members of a company managed by hand in EPC, or that would move a member into such a company, are accepted and not applied (skipped: company_hrms_sync_disabled) Retter 19 Oct 2026

---

Definitions & List of Abbreviations

Abbreviation Description
HRMS Human Resource Management System
EPC Emirates Platinum Card
API Application Programming Interface
SSM AWS Systems Manager (Parameter Store)

---

1. Interface Description

When employee data changes in the HRMS (name, email, phone, grade, status, etc.), the HRMS system will push the updates to the Platinum Application. This ensures that member profiles remain synchronized with the authoritative HR data source.

Business Value

Objective

> Standardized Payload: HRMS should always send the full employee record in every request. The EPC system overwrites the member record with the incoming HRMS data.

---

2. Assumptions & Risk

Assumptions

Risks

Risk Mitigation
Network timeouts between HRMS and EPC Configure appropriate timeout settings (recommended: 30s)
Employee not found in EPC HRMS should handle 404 responses gracefully and log for review

---

3. Non-Functional Requirements

3.1 Security Requirements

Sr No. Non-Functional Requirement Value
1 PHI or Credit Card data? No credit card data & no patient health information
2 Authentication Pattern API Key (X-API-Key header)
3 Secure Channel / Encryption in Transit TLS 1.2+ (HTTPS only)
4 Input validation Yes - all fields validated via JSON Schema
5 Internet exposed? IP whitelisting? Yes, exposed via CloudFront. IP whitelisting can be implemented via WAF rules
6 Logging All requests logged with sanitized payloads (sensitive fields redacted)
7 Data exposure Only necessary fields returned. Sensitive member data not included in response

---

4. Solution View

4.1 Logical

Component Value
Source HRMS (Human Resource Management System)
Source Protocol HTTPS REST API
Source Data Format JSON
Target EPC (Emirates Platinum Card)
Target Protocol HTTPS
Target Data Format JSON

4.2 Architecture

4.2.1 Interface Architecture

┌─────────────┐                              ┌─────────────┐
│             │         HTTPS / JSON         │             │
│    HRMS     │  ─────────────────────────▶  │   EPC API   │
│   (Source)  │            POST              │   (Target)  │
│             │  ◀─────────────────────────  │             │
└─────────────┘         HTTPS / JSON         └─────────────┘

Flow:

4.2.2 Security Mechanisms

4.2.3 Exception/Error Management Guidelines

API Monitoring

Exception Handling

HTTP Status Scenario HRMS Action
200 Success Log success, continue
400 Validation error Fix request data, retry
401 Invalid API key Check API key, contact EPC team
404 Employee not found, or companyId (BG_ID) not mapped to any Platinum company Log for manual review
409 companyId (BG_ID) resolves to a company of a different group type than the member's current company Log for manual review; do not retry without correction
500 Server error Retry with backoff
503 Service unavailable Retry later

4.3 Interface Touchpoints / Use Cases

4.3.1 Employee Profile Update

Actors: HRMS System (automated)

Trigger: Employee data change in HRMS (name, email, phone, grade, address)

Flow:

4.3.2 Staff ID Migration

Actors: HRMS System (automated)

Trigger: Employee's staff ID changes in HRMS

Flow:

4.3.3 Employee Termination

Actors: HRMS System (automated)

Trigger: Employee status changes to terminated/inactive in HRMS

Flow:

4.3.4 Employee Reactivation

Actors: HRMS System (automated)

Trigger: Previously terminated employee is rehired

Flow:

4.3.5 Company / Business Group Reassignment

Actors: HRMS System (automated)

Trigger: Employee moves to a different business group in HRMS

Flow:

4.3.6 Member Not Registered Through HRMS

Trigger: The staff ID belongs to a member who registered another way (self-registered, associate company or created in the back office)

Flow:

4.3.7 Company Managed by Hand in EPC

Trigger: The member belongs to a company whose EPC setting "Disable integrations and self-registrations" is on, or companyId (BG_ID) resolves to such a company while the member belongs to another one

Flow:

---

4.4 Fields Definition

Request Fields

> Null convention: For optional fields that have no value, send null — not an empty string (""). Empty strings are rejected by validation.

>

> Full-record convention: HRMS should always send the full employee record in every request. The EPC system overwrites the member record with the incoming HRMS data.

>

> Exception — joiningDate, maritalStatus and addressOptional are retained, not cleared: for these fields omitting the key, or sending null (or an empty string for maritalStatus and addressOptional), means *"no value supplied"* rather than *"clear this value"*. EPC keeps whatever value it already holds (from a previous push, or from the outbound getEmployeeDetails fetch). Every other nullable field follows the same retention rule in practice, but these are the fields where HRMS may legitimately omit the key entirely.

>

> Same rules on every HRMS path (EPC-1290): this push, the dependant push and the back office "Update HRMS data" pull apply one rule set, so the same HRMS record always gives the same member record.

Field Type Required Description Example
employeeId String Yes Employee's current staff ID (primary lookup key) "EK123456"
name String Yes Employee's first name "John"
middleName String Optional Employee's middle name "William"
surname String Yes Employee's last name "Doe"
email String Yes Employee's email address (must be valid email format). Not written when the member's current email is on an SSO domain, or when another member already uses this address; the rest of the request is still applied and the skip is recorded in the member's history "john.doe@emirates.com"
phone String Yes Employee's phone number "+971501234567"
grade String Yes Employee's job grade "EK.07"
employmentType String Yes Type of employment. Must match an active member type configured in the backoffice. Returns 400 if invalid. "EMP"
status String Yes HR status: "active", "inactive", "terminated" "active"
address Object Yes Address information See below
address.country String Yes Country (Staff Cost Centre belongs to) "Emirates Group - UAE"
address.address String Yes HOME address (CUR_RES_ADDRESS). Stored as the member's home address "Al Nahda, Dubai"
addressOptional String Optional WORK location (WORK_LOC_ADDRESS). Stored as the member's work address. Omitted, null or empty leaves the stored work address unchanged "Dubai Airport Free Zone"
birthdate String (date) Yes Birth date. Accepts YYYY-MM-DD, the HRMS form 1990-01-15 00:00:00.0 or a date-time with an offset such as 1990-01-15T00:00:00.000+04:00. Stored as the date part, YYYY-MM-DD, never converted to another time zone "1990-01-15"
gender String Yes Employee's gender: M, F, Male or Female (any case). Any other value returns 400 "Male"
maritalStatus String Optional / Nullable Employee's marital status, any case. M or Married is stored as married. S, Single, Divorced, Widowed or Separated is stored as single. Any other value keeps the stored marital status and is recorded in the member's history. Never returns 400. Changing to married deactivates the member's active companion. See the retention note above "Married"
coreGrade String Yes Core grade code "EK.07"
dependantsExists String Yes Whether employee has dependants ("Y" or "N") "Y"
oldStaffId String Nullable Previous staff ID (for migration scenarios) "EK000001"
lastDayOfService String (date) Nullable Termination date (ISO 8601) "2026-03-31"
leavingReason String Nullable Reason for leaving (terminations) "Retirement"
joiningDate String (date) Optional / Nullable Date employment started (HRMS JOINING_DATE). Accepts YYYY-MM-DD or the raw HRMS form 2008-09-23 00:00:00.0; both are stored as YYYY-MM-DD. A present-but-unparseable value returns 400. See the retention note above. "2008-09-23"
companyId String Yes HRMS Business Group ID (BG_ID). Always send the employee's current BG_ID. The member is reassigned to the Platinum company whose bgId matches this value; sending the unchanged BG_ID is a no-op. Returns 404 (code 11016) if unmapped, 409 (code 11017) on group-type mismatch. "61"

Response Fields

Field Type Description
success Boolean True if operation succeeded
message String Human-readable message
body.memberId String (UUID) Member's ID in EPC system
body.staffId String Current staff ID
body.updatedFields Array[String] List of fields that were updated
body.staffIdMigrated Boolean True if staff ID was migrated
body.skipped String Present when the push was accepted but not applied; updatedFields is then empty. not_hrms_registered: member not registered through HRMS. company_hrms_sync_disabled: the member's company, or the company the BG_ID points to, is managed by hand in EPC

---

4.5 Request/Response Samples

Security / Credentials

Authentication: API Key via X-API-Key header

X-API-Key: <your-api-key>
Content-Type: application/json

4.5.1 Standardized Full Payload

HRMS should always send the complete employee record with every request. The EPC system overwrites the member record with the incoming HRMS data. The updatedFields array in the response tells HRMS which fields were modified.

> Null convention: For fields that have no value, send null — not an empty string (""). Empty strings are rejected by validation.

Request:

POST /members/hr/employee HTTP/1.1
Host: uat.api.platinum.retter.io
X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "employeeId": "EK123456",
  "oldStaffId": null,
  "email": "john.doe@emirates.com",
  "phone": "+971501234567",
  "name": "John",
  "middleName": "William",
  "surname": "Doe",
  "grade": "EK.07",
  "employmentType": "EMP",
  "status": "active",
  "address": {
    "country": "Emirates Group - UAE",
    "address": "Al Nahda, Dubai"
  },
  "addressOptional": "Dubai Airport Free Zone",
  "lastDayOfService": null,
  "birthdate": "1990-01-15",
  "gender": "Male",
  "maritalStatus": "Married",
  "dependantsExists": "Y",
  "coreGrade": "EK.07",
  "joiningDate": "2008-09-23",
  "leavingReason": null,
  "companyId": "61"
}

Response (200 OK) — only grade and phone differed from current record:

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK123456",
    "updatedFields": ["phone", "grade"]
  }
}

Response (200 OK) — nothing changed (all values match current record):

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK123456",
    "updatedFields": []
  }
}

Response (200 OK) — member not registered through HRMS, push not applied:

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK123456",
    "updatedFields": [],
    "skipped": "not_hrms_registered"
  }
}

Response (200 OK) — member's company managed by hand in EPC, push not applied:

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK123456",
    "updatedFields": [],
    "skipped": "company_hrms_sync_disabled"
  }
}

4.5.2 Scenario Detection Notes

Scenario Key Fields Response Indicator
Profile Update Any non-null field updatedFields lists written fields
Staff ID Migration oldStaffId provided, member found by oldStaffId staffIdMigrated: true in response
Termination status: "terminated" or "inactive" updatedFields includes "status"
Reactivation status: "active" (member currently Inactive, deactivated by HRMS) updatedFields includes "status"

Staff ID Migration example — employee's ID changed from EK123456 to EK999999:

{
  "employeeId": "EK999999",
  "oldStaffId": "EK123456",
  "email": "john.doe@emirates.com",
  "phone": "+971501234567",
  "name": "John",
  "surname": "Doe",
  "grade": "EK.07",
  "employmentType": "EMP",
  "status": "active",
  "...": "... (all other fields)"
}

Response:

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK999999",
    "updatedFields": ["staffId", "previousStaffIds"],
    "staffIdMigrated": true
  }
}

Termination example — status changed to "terminated":

{
  "employeeId": "EK123456",
  "status": "terminated",
  "leavingReason": "Retirement",
  "lastDayOfService": "2026-03-31",
  "...": "... (all other fields)"
}

Response:

{
  "success": true,
  "message": "Employee updated successfully.",
  "body": {
    "memberId": "550e8400-e29b-41d4-a716-446655440000",
    "staffId": "EK123456",
    "updatedFields": ["status", "statusReason"]
  }
}

---

4.6 Error Responses

400 - Validation Error

{
  "success": false,
  "error": {
    "code": 10001,
    "message": "Validation error"
  },
  "details": {
    "errors": {
      "employeeId": ["Required"]
    }
  }
}

401 - Unauthorized (Invalid API Key)

{
  "success": false,
  "error": {
    "code": 10072,
    "message": "Invalid API key"
  }
}

404 - Employee Not Found

{
  "success": false,
  "error": {
    "code": 10073,
    "message": "Employee not found"
  }
}

404 - Company (BG_ID) Not Found

Returned when companyId is non-null but no Platinum company is configured with that HRMS Business Group ID.

{
  "success": false,
  "error": {
    "code": 11016,
    "message": "No Platinum company is mapped to the supplied HRMS business group id (BG_ID)."
  }
}

409 - Company Group Type Mismatch

Returned when the company resolved from companyId belongs to a different group type (internal ↔ external) than the member's current company.

{
  "success": false,
  "error": {
    "code": 11017,
    "message": "Cannot move member: target company belongs to a different company group type."
  }
}

500 - Internal Server Error

{
  "success": false,
  "error": {
    "code": 10000,
    "message": "Internal server error"
  }
}

---

5. API Endpoints

Environment URL
Staging https://staging.api.platinum.retter.io/members/hr/employee
UAT https://uat.api.platinum.retter.io/members/hr/employee

API Documentation

---

6. Appendix

6.1 Member Status Values

Status Description
Active Member is active and can use benefits
Inactive Member is deactivated (terminated/suspended)
Pending Member registration pending (not applicable for HR updates)

6.2 Sync Log Tracking

All HR integration calls are logged with:

6.3 Audit Trail

Successful updates create audit log entries with: