Employee Sync
Use this API to upsert employees from an external system. The operation is
idempotent by syncId, so re-sending the same employee updates the existing
record instead of creating a duplicate.
At A Glance
/v2/employee/sync-upsert| Area | Detail |
|---|---|
| Base URL | https://api.mulltiply.org |
| Content type | application/json |
| Request body | Single employee object or array of employee objects |
| Upsert key | syncId |
| Processing mode | Asynchronous background processing |
How Upsert Works
- Every employee must include
syncId, your stable external identifier. - If an employee with that
syncIdalready exists in the workspace, it is updated. - If the
syncIdis new, a new employee is created and thesyncIdis stored. - Re-sending the same employee data is safe and does not create duplicates.
- The request returns after validation; create/update work is queued in the background.
Request Fields
| Field | Required | Type | Default | Meaning |
|---|---|---|---|---|
syncId | Yes | string or number | - | Stable external ID and upsert key. |
name | Yes | string | - | Employee full name. |
phone | Recommended | string | - | Login identifier; should be provided and unique. |
countryCode | No | string | 91 | Dialing country code without +. |
email | No | string | - | Employee email. |
type | No | string | Sales_Person | Employee role type. |
city | No | string | - | Employee city. |
employeeCode | No | string | - | Internal employee code; must be unique within the store. |
allowOrderPlace | No | boolean | true | Whether the employee can place orders for shops. |
shopTags | No | array of strings | - | Tags used to match employee to shops. |
department | No | string | - | Department name, resolved by company. |
designation | No | string | - | Designation name, resolved by company. |
margEmployeeId | No | string or number | null | Legacy external ID, stored but not used for matching. |
leaveBalance | No | array | [] | Opening leave balances. |
Do not send internal foreign keys such as workspaceRoleId, roleWeight,
departmentId, designationId, or reportingManagerId. These are resolved by
the API from the provided fields where possible.
Employee Types
type maps to the employee's permission and workspace role. Supported values:
Sales_PersonDelivery_PersonManagerEmployeeSupervisorCustomer_CareMarketingHR
If type is omitted, it defaults to Sales_Person. If the type does not
resolve to a role in the workspace, the employee falls back to the workspace's
default role.
Shop Tags
shopTags links employees to shops without assigning shops one by one.
- Each tag is a free-form string such as
city: Demo Cityorbeat: South. - Matching is exact;
city: Demo Citydoes not match onlyDemo City. - An employee handles every shop whose tags overlap with the employee's
shopTags. - An employee with
shopTagsis resolved by tag matching even if no shops match yet. - An employee without
shopTagsfalls back to explicit shop assignments, if any exist.
Example Requests
- Minimal
- Full
- Batch
{
"syncId": "EXT-1001",
"name": "Demo Sales Employee",
"phone": "9999902001"
}
{
"syncId": "EXT-1001",
"name": "Demo Sales Employee",
"phone": "9999902001",
"countryCode": "91",
"email": "employee@example.com",
"type": "Sales_Person",
"city": "Demo City",
"employeeCode": "EMP-1001",
"allowOrderPlace": true,
"shopTags": ["city: Demo City", "beat: South"],
"department": "Sales",
"designation": "Field Executive",
"margEmployeeId": "LEGACY-1001"
}
[
{
"syncId": "EXT-1001",
"name": "Demo Sales Employee",
"phone": "9999902001",
"type": "Sales_Person",
"shopTags": ["city: Demo City"]
},
{
"syncId": "EXT-1002",
"name": "Demo Delivery Employee",
"phone": "9999902002",
"type": "Delivery_Person",
"city": "Sample City"
}
]
Response
The response is returned immediately after validation. Processing continues in the background.
{
"count": 2,
"processable": 2,
"message": "Syncing employees, you will be notified once done"
}
| Field | Meaning |
|---|---|
count | Total number of rows received. |
processable | Number of rows that passed validation and were queued. |
message | Human-readable status. |
nonProcessableRows | Present only when rows failed validation. Shows rejected rows and reasons. |
If more than 20 rows fail, only the first 20 are returned in
nonProcessableRows; the full list is recorded in the bulk upload log.
Validation Errors
Rows that fail validation are not processed. Valid rows in the same request still continue.
{
"row": 3,
"itemName": "Some Name or phone",
"errors": ["syncId is required and must be a non-empty value"]
}
Common validation messages:
name is required and must be a non-empty stringsyncId is required and must be a non-empty valueshopTags must be an arrayallowOrderPlace must be a booleanmargEmployeeId must be a string or numberleaveBalance must be an array
If every row fails validation, processable is 0, nonProcessableRows lists
the failures, and nothing is queued.
Behavior Notes
| Behavior | Detail |
|---|---|
| Idempotency | Re-sending the same syncId updates the employee in place. |
| Partial success | Invalid rows are skipped and reported; valid rows still sync. |
| Large payloads | Supported because work is queued and processed asynchronously in chunks. |
| Updates | Existing employee records are modified; a new user is not created for an existing syncId. |
Implementation Checklist
- Provide
syncIdfor every employee. - Provide
namefor every employee. - Provide unique phone numbers when employees need login access.
- Use supported
typevalues. - Send
shopTagsas an array of exact tag strings. - Do not send internal role, department, designation, or reporting manager IDs.
- Expect asynchronous processing after initial validation.