Upload the employee directory

Adds directory contacts from a one-sheet .xlsx file.

POSThttps://api.spyne.ai/console/v1/product-onboarding/vini/directory/file
AuthBearer token (console user)Rate limitNot documentedProcessingSynchronous. Parses the file, then waits for the directory write (30 s timeout).

Accepts one .xlsx file of up to 20 MB with a single sheet.

Required columns:

  • name (or full_name), or first_name
  • role
  • department
  • phone_number (or phone)
  • isd_code (or isdcode / isd)

Optional columns: last_name, extension, email.

Headers are matched after lower-casing and replacing non-letters with _. A + is added to isd_code if missing. Phones must be 7 to 15 digits.

If any row fails, nothing is saved. The call instead stores an error copy of the file with an errors column, and returns a download link valid for 24 hours. If all rows pass, the contacts are sent to the directory by department name. Missing departments are created, and exact duplicates are skipped. The call does not update any checklist task.

Before you call it

  • You need enterpriseId and teamId. Send them as multipart text fields.

  • Use the template file if you have it. A 400 for missing columns returns the template link in errorFileUrl.

  • Put the text fields before the file part. The UI sends the file first. To be confirmed: whether text fields sent after the file reach the endpoint. If they do not, the call returns 400 enterpriseId and teamId are required for directory creation.

  • 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. Parses the file, then waits for the directory write (30 second timeout).


Request

Requiredalways sendOptionalcan be left out
Request checklist
  1. Build multipart/form-data with enterpriseId, teamId, teamName, then file.
  2. Make sure the workbook has exactly one sheet and at least one data row.
  3. On 400 with errorFileUrl, download the file, fix the rows listed in its errors column, and upload again.
  4. Note that the UI does not mark the Employee Directory task after an upload. To mark it, call Mark a checklist task done with {teamId, taskName: "Employee Directory", isCompleted: true}.
ParameterTypeRequiredDescription
Headers——Sent as HTTP headers.
AuthorizationstringRequiredBearer YOUR_TOKEN
Content-TypestringRequiredmultipart/form-data (set by your HTTP client)
Body (multipart form fields)——Sent as multipart/form-data fields.
enterpriseIdtextRequiredDealer group ID.
teamIdtextRequiredRooftop ID.
teamNametextOptionalSent by the UI. Not used.
filefileRequiredOne .xlsx file, up to 20 MB, one sheet.

Sample request

curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/vini/directory/file" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -F "enterpriseId=<enterpriseId>" \
  -F "teamId=<teamId>" \
  -F "teamName=Example Motors" \
  -F "[email protected];type=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
import requests

with open("employee-directory.xlsx", "rb") as fh:
    res = requests.post(
        "https://api.spyne.ai/console/v1/product-onboarding/vini/directory/file",
        headers={"Authorization": "Bearer YOUR_TOKEN"},
        data={"enterpriseId": "<enterpriseId>", "teamId": "<teamId>", "teamName": "Example Motors"},
        files={"file": ("employee-directory.xlsx", fh,
                        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")},
    )
print(res.status_code, res.json())
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append("enterpriseId", "<enterpriseId>");
form.append("teamId", "<teamId>");
form.append("teamName", "Example Motors");
form.append(
  "file",
  new Blob([await readFile("employee-directory.xlsx")], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  }),
  "employee-directory.xlsx"
);
const res = await fetch("https://api.spyne.ai/console/v1/product-onboarding/vini/directory/file", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_TOKEN" },
  body: form,
});
console.log(res.status, await res.json());

Sample response

{
  "success": true,
  "error": false,
  "message": "Users uploaded and processed successfully.",
  "data": {
    "totalUsers": 12,
    "invitedUsers": 0,
    "directoryUsers": 12,
    "inviteUsersApiCalled": false,
    "directoryApiCalled": true,
    "inviteUsersStatusCode": null,
    "directoryStatusCode": 200
  }
}
{
  "error": true,
  "message": "Errors found in uploaded Excel file.",
  "errorFileUrl": "https://<signed-download-url>",
  "errorFileKey": "product-onboarding/users-directory/errors/<timestamp>-<id>-employee-directory.xlsx"
}
{
  "error": true,
  "message": "Missing required columns in .xlsx file.",
  "missingColumns": ["name_or_first_name", "isd_code"],
  "errorFileUrl": "https://<template-file-url>"
}
{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }
{ "error": true, "message": "Unexpected error while processing users file." }

400 Bad Request (missing columns). Other 400 messages from this endpoint:

  • No file uploaded. Provide one .xlsx file in `file` field.
  • Only one file is allowed.
  • Invalid file format. Only .xlsx is supported.
  • Found multiple sheets. Only one sheet is allowed.
  • Uploaded .xlsx file does not contain any sheets.
  • Uploaded .xlsx file is empty.
  • enterpriseId and teamId are required for directory creation.

The directory write's 400 errors (for example an invalid phone) are passed through with the shape shown under Add directory contacts.

Response fields

ParameterTypeDescription
successbooleantrue on 200.
data.totalUsers / directoryUsersnumberRows sent to the directory. Exact duplicates are skipped by the directory and still counted here.
data.directoryStatusCodenumber or nullStatus of the directory write.
errorFileUrlstringOn 400: a 24-hour download link to the error copy, or the template link when columns are missing.
errorFileKeystringOn 400 row errors: the stored error file key.
missingColumnsstring[]On 400 missing columns.

Errors

StatusReasonWhen it happens
400File checksNo file, more than one file, not .xlsx, more than one sheet, no sheet, or no rows.
400Missing required columns in .xlsx file.A required column is missing.
400Errors found in uploaded Excel file.One or more rows failed. Nothing is saved.
400enterpriseId and teamId are required for directory creation.IDs missing from the form fields.
400Passed through from the directory writee.g. a phone number that is not valid with its country code.
401ERROR_AUTH_401Missing or invalid token.
500Unexpected errorParse failure, a file over 20 MB, or a failure storing the error file.

Next

Refresh with List the employee directory. The UI does not mark the Employee Directory task after an upload. If the upload is the only way the rooftop adds contacts, call Mark a checklist task done with {teamId: "<teamId>", taskName: "Employee Directory", isCompleted: true}.


Did this page help you?