ICD - HRMS - EPC - Dependant 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 dependant data Retter 10 Feb 2026
1.2 Draft Added status field for dependant activation/deactivation Retter 10 Feb 2026
1.3 Draft Changed to upsert mode — creates dependant if not found Retter 11 Feb 2026
1.4 Draft Made email field nullable; clarified type field uses dynamic back-office mapping (hrmsMapping) Retter 30 Mar 2026
1.5 Draft Status field changed to "Active"/"In-Active" (case-insensitive); unrecognized type no longer rejects — saves without mapping and returns warning Retter 30 Mar 2026
1.6 Draft Added optional, nullable phone field (dependant mobile number) Retter 14 Jun 2026
1.7 Draft EPC-1289: added optional middleName, gender and address (address, country); missing values are read from the HRMS dependant lookup; pushes for primaries not registered through HRMS are accepted and not applied (skipped) Retter 16 Oct 2026
1.8 Draft EPC-1290: birthdate is stored (it always was; "not stored" was wrong) as YYYY-MM-DD, from any of the date forms HRMS sends. "Active" reactivates only a dependant HRMS deactivated. The email is not written when another member already uses it Retter 20 Oct 2026
1.9 Draft EPC-1259: pushes whose primary belongs to a company managed by hand in EPC 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 dependant data changes in the HRMS (name, email, relationship type, etc.), the HRMS system will push the updates to the Platinum Application. This endpoint operates in upsert mode: if the dependant exists it is updated; if not, a new dependant is created under the primary member.

Business Value

Objective

> Standardized Payload: HRMS should always send the full dependant record in every request. The EPC system overwrites the dependant record with the incoming HRMS data, or creates a new dependant if the ID is not found.

---

2. Assumptions & Risk

Assumptions

Risks

Risk Mitigation
Network timeouts between HRMS and EPC Configure appropriate timeout settings (recommended: 30s)
Duplicate dependant ID EPC rejects creation if the ID already exists for a different member (403)
Dependant ownership mismatch HRMS should verify dependant-employee relationship before sending updates

---

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 Dependant updated Log success, continue
201 Dependant created (did not exist) Log success, store returned dependantId
400 Validation error Fix request data, retry
401 Invalid API key Check API key, contact EPC team
403 Dependant ownership mismatch Verify dependant belongs to employee
404 Primary member not found Log for manual review
500 Server error Retry with backoff
503 Service unavailable Retry later

4.3 Interface Touchpoints / Use Cases

4.3.1 Dependant Profile Upsert

Actors: HRMS System (automated)

Trigger: Dependant data change or new dependant in HRMS

Flow:

4.3.2 Dependant Name Change

Actors: HRMS System (automated)

Trigger: Dependant's name changes in HRMS (e.g., after marriage)

Flow:

4.3.3 Dependant Relationship Type Change

Actors: HRMS System (automated)

Trigger: Dependant's relationship type changes in HRMS

Flow:

4.3.4 Middle Name, Gender and Address (EPC-1289)

Actors: HRMS System (automated)

Trigger: Any dependant push

Flow:

4.3.5 Primary Not Registered Through HRMS

Actors: HRMS System (automated)

Trigger: employeeId belongs to a primary who registered another way (self-registered, associate company or created in the back office)

Flow:

4.3.6 Primary's Company Managed by Hand in EPC

Actors: HRMS System (automated)

Trigger: employeeId belongs to a primary whose company has the EPC setting "Disable integrations and self-registrations" on

Flow:

---

4.4 Fields Definition

Request Fields

> All fields except phone must be present in the payload. HRMS must always send the full dependant record in every request. The EPC system overwrites the dependant record with the incoming HRMS data. email and phone accept null when not available. Empty strings are rejected by validation (except email/phone, where empty/whitespace is normalized to null).

Field Type Required Description Example
id String Yes Dependant's ID in the EPC system "660e8400-e29b-41d4-a716-446655440001"
employeeId String Yes Primary member's staff ID (to verify ownership) "EK123456"
status String (enum) Yes "Active" or "In-Active" (case-insensitive). "In-Active" sets member status to Inactive; "Active" reactivates if Inactive and the deactivation came from HRMS. A dependant the Platinum programme team deactivated or removed stays Inactive. "Active"
name String Yes Dependant's first name "Jane"
surname String Yes Dependant's last name "Doe"
email String or null Yes Dependant's email address. Must be valid email format if provided; send null if not available. Not written when another member already uses this address; the rest of the request is still applied and the skip is recorded in the dependant's history. "jane.doe@example.com" or null
phone String or null No Dependant's mobile number. Optional — may be omitted. Send null (or omit) if not available; when null/omitted the stored phone is left unchanged. "+971501234567" or null
type String Yes Relationship type. Member subtypes are defined dynamically in the back office by admins. A mapping field (hrmsMapping) is used to match HRMS values to EPC values. If the value is not recognized, the dependant is still saved but without type mapping, and a warning is returned in the warnings array. "Wife"
birthdate String (date) Yes Birth date. Accepts YYYY-MM-DD, the HRMS form 1995-05-15 00:00:00.0 or a date-time with an offset such as 1995-05-15T00:00:00.000+04:00. Stored as the date part, YYYY-MM-DD, never converted to another time zone "1995-05-15" or "1995-05-15 00:00:00.0"
middleName String or null No Dependant's middle name (DEP_MIDDLE_NAMES). Omitted, null or empty leaves the stored value unchanged "Marie"
gender String or null No Dependant's sex (DEP_SEX): M, F, Male or Female, case-insensitive. Omitted, null or empty leaves the stored value unchanged; any other value is ignored with a warning "Female"
address Object or null No Dependant's home address. Each part optional See below
address.address String or null No One line: address lines, town or city, postal code "Villa 12, Al Wasl Road, Dubai"
address.country String or null No DEP_COUNTRY as an ISO alpha-2 code or country name; an unrecognised value is ignored with a warning "AE"

Response Fields

Field Type Description
success Boolean True if operation succeeded
message String Human-readable message
body.dependantId String (UUID) Dependant's ID in EPC system
body.primaryMemberId String (UUID) Primary member's ID in EPC system
body.updatedFields Array[String] List of fields that were updated
body.warnings Array[String] (optional) Warnings about the request (e.g., unrecognized type, gender or country). Only present when there are warnings.
body.skipped String (optional) Present when the push was accepted but not applied; updatedFields is then empty. not_hrms_registered: primary not registered through HRMS. company_hrms_sync_disabled: the primary's company 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 dependant record with every request. The EPC system overwrites the dependant record with the incoming HRMS data, or creates a new dependant if the ID is not found. The updatedFields array in the response tells HRMS which fields were modified. An empty updatedFields with a 201 status indicates a newly created dependant.

> Null convention: For fields that support null (e.g., email), send null — not an empty string (""). Empty strings are rejected by validation.

Request:

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

{
  "id": "660e8400-e29b-41d4-a716-446655440001",
  "employeeId": "EK123456",
  "status": "Active",
  "type": "Wife",
  "name": "Jane",
  "surname": "Doe",
  "email": "jane.doe@example.com",
  "phone": "+971501234567",
  "birthdate": "1995-05-15",
  "middleName": "Marie",
  "gender": "Female",
  "address": {
    "address": "Villa 12, Al Wasl Road, Dubai",
    "country": "AE"
  }
}

Response (200 OK) — dependant existed, only name and email differed:

{
  "success": true,
  "message": "Dependant updated successfully",
  "body": {
    "dependantId": "660e8400-e29b-41d4-a716-446655440001",
    "primaryMemberId": "550e8400-e29b-41d4-a716-446655440000",
    "updatedFields": ["name", "email"]
  }
}

Response (200 OK) — dependant existed, nothing changed:

{
  "success": true,
  "message": "Dependant updated successfully",
  "body": {
    "dependantId": "660e8400-e29b-41d4-a716-446655440001",
    "primaryMemberId": "550e8400-e29b-41d4-a716-446655440000",
    "updatedFields": []
  }
}

Response (201 Created) — dependant did not exist, created under primary member:

{
  "success": true,
  "message": "Dependant added successfully.",
  "body": {
    "dependantId": "660e8400-e29b-41d4-a716-446655440001",
    "primaryMemberId": "550e8400-e29b-41d4-a716-446655440000",
    "updatedFields": []
  }
}

---

4.6 Error Responses

400 - Validation Error

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

401 - Unauthorized (Invalid API Key)

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

403 - Dependant Ownership Mismatch

{
  "success": false,
  "error": {
    "code": 10074,
    "message": "Dependant does not belong to the specified employee"
  }
}

404 - Primary Member Not Found

{
  "success": false,
  "error": {
    "code": 10075,
    "message": "Primary member not found"
  }
}

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/dependant
UAT https://uat.api.platinum.retter.io/members/hr/dependant

API Documentation

---

6. Appendix

6.1 Sync Log Tracking

All HR integration calls are logged with:

6.2 Audit Trail

Successful operations create audit log entries with: