Add directory contacts
Adds one or more contacts to the rooftop's employee directory from a JSON list.
Validates each user, then sends the contacts to the directory as one batch:
- The phone is built as
isdCode+phoneNumberand must be a valid number with country code. - Contacts that exactly match an existing contact (same department, name, designation, phone and extension) are skipped.
- If a department is given by name instead of ID, missing departments are created.
The response reports how many users were processed. It does not return the new contact IDs. The call does not update any checklist task.
Before you call it
-
You need
enterpriseIdandteamId. -
Get department IDs from the rooftop's department list. The UI matches the department name to an ID. If nothing matches, it sends the name in
departmentId, and a name sent there fails (see Errors). -
All users in one request must use the same kind of department reference: either all IDs or all names.
-
Authentication: Bearer token of a signed-in console user. The token, and any cookie on the request, are forwarded to the directory write.
-
Rate limit: Not documented
-
Processing: Synchronous. Waits for the directory write (30 second timeout).
Request
- Each user needs
firstName,role,departmentId,isdCodeandphoneNumber. - Send
isdCodewith a leading+, e.g.+1. - On 2xx, call Mark a checklist task done with
{teamId, taskName: "Employee Directory", isCompleted: true}.
| Parameter | Type | Required | Description |
|---|---|---|---|
| Headers | — | — | Sent as HTTP headers. |
Authorization | string | Required | Bearer YOUR_TOKEN |
Content-Type | string | Required | application/json |
| Body | — | — | Sent as a JSON body. |
enterpriseId | string | Required | Dealer group ID. Without it the call returns 400. |
teamId | string | Required | Rooftop ID. Without it the call returns 400. |
teamName | string | Optional | Sent by the UI. Not used. |
users | array | Required | Non-empty list of contacts. |
users[].firstName | string | Required | First name. |
users[].lastName | string | Optional | Last name. |
users[].role | string | Required | Job title. It is stored as designation. designation is accepted in its place. |
users[].departmentId | string | Required | Department ID, a positive integer. department_id is also accepted. |
users[].isdCode | string | Required | Country code, e.g. +1. |
users[].phoneNumber | string | Required | Number without country code. phone_number or phone are also accepted. |
users[].extension | string | Optional | Extension. |
users[].email | string | Optional | Email. |
Sample request
curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/vini/directory/manual" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"teamName": "Example Motors",
"users": [
{ "firstName": "Jane", "lastName": "Doe", "role": "Service Advisor", "departmentId": "<departmentId>",
"isdCode": "+1", "phoneNumber": "5550100000", "extension": "204", "email": "[email protected]" }
]
}'import requests
payload = {
"enterpriseId": "<enterpriseId>",
"teamId": "<teamId>",
"teamName": "Example Motors",
"users": [{
"firstName": "Jane", "lastName": "Doe", "role": "Service Advisor",
"departmentId": "<departmentId>", "isdCode": "+1", "phoneNumber": "5550100000",
"extension": "204", "email": "[email protected]",
}],
}
res = requests.post(
"https://api.spyne.ai/console/v1/product-onboarding/vini/directory/manual",
json=payload,
headers={"Authorization": "Bearer YOUR_TOKEN"},
)
print(res.status_code, res.json())const res = await fetch("https://api.spyne.ai/console/v1/product-onboarding/vini/directory/manual", {
method: "POST",
headers: { Authorization: "Bearer YOUR_TOKEN", "Content-Type": "application/json" },
body: JSON.stringify({
enterpriseId: "<enterpriseId>",
teamId: "<teamId>",
teamName: "Example Motors",
users: [{
firstName: "Jane", lastName: "Doe", role: "Service Advisor", departmentId: "<departmentId>",
isdCode: "+1", phoneNumber: "5550100000", extension: "204", email: "[email protected]",
}],
}),
});
console.log(res.status, await res.json());Sample response
{
"success": true,
"error": false,
"message": "Users processed successfully.",
"data": {
"totalUsers": 1,
"invitedUsers": 0,
"directoryUsers": 1,
"inviteUsersApiCalled": false,
"directoryApiCalled": true,
"inviteUsersStatusCode": null,
"directoryStatusCode": 200
}
}{
"error": true,
"message": "Some items are missing required values.",
"validationErrors": [{ "rowNumber": 1, "missingFields": ["isdCode", "phone_number"] }]
}{ "message": "Department(s) not found for enterprise/team: 99", "error": true, "code": "ERROR_BAD_REQ_400", "details": null, "data": null }{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }{ "error": true, "message": "timeout of 30000ms exceeded" }400 Bad Request (row validation). Other 400 messages from this endpoint:
Provide a non-empty array in `users`.enterpriseId and teamId are required for directory creation.
400 Bad Request (directory write, passed through). Other passed-through 400 messages:
Invalid entry at index 0. "phone" value "..." must be a valid phone number with country code, e.g. +1<number>Invalid entry at index 0. departmentId must be a valid positive integerAll contacts in a request must use either department or departmentId
Response fields
| Parameter | Type | Description |
|---|---|---|
success | boolean | true on 200. |
data.totalUsers | number | Users accepted for the directory. |
data.directoryUsers | number | Same as totalUsers. |
data.directoryApiCalled | boolean | true when the batch was sent. |
data.directoryStatusCode | number or null | Status of the directory write. |
data.invitedUsers, inviteUsersApiCalled, inviteUsersStatusCode | number / boolean / null | Always 0, false and null. No console invites are sent from here. |
Errors
| Status | Reason | When it happens |
|---|---|---|
400 | Provide a non-empty array in users | users is missing or empty. |
400 | Some items are missing required values. | A user is missing firstName, role, departmentId, isdCode or the phone. validationErrors lists them by row. |
400 | enterpriseId and teamId are required for directory creation. | IDs are missing from the body. |
400 | Passed through from the directory write | Invalid phone, departmentId not a positive integer (for example a department name), a department not on this rooftop, or mixed ID and name references. |
401 | ERROR_AUTH_401 | Missing or invalid token. |
500 | Unexpected error | The directory write timed out or failed without a response. |
Next
On 2xx, call Mark a checklist task done with {teamId: "<teamId>", taskName: "Employee Directory", isCompleted: true}. The UI does this without waiting for the result. Refresh with List the employee directory. Directory contacts can be picked as the authorized representative on the brand registration.
- Called before: List the employee directory.
- Called after: Mark a checklist task done, Submit or save the brand registration.
Updated about 1 hour ago
