Save departments, hours and holidays

Creates or updates the rooftop's departments, hours and holidays, and pushes them to the live agent.

POSThttps://api.spyne.ai/console/v1/product-onboarding/vini/departments
AuthBearer token (console user)Rate limitNot documentedProcessingSynchronous. Pushes run in sequence and are not rolled back.

The request is passed through as-is to the department settings save, using your token. That save does the following, in order:

  1. Resolves copy markers. isSameAsSales / isSameAsService on built-in departments and sameAs on custom departments copy another department's hours. address.sameAs copies another department's address. sameAs names that are not departments, such as "rooftop address", are stored as-is.
  2. If holidays is sent, pushes the holidays to the live agent. Holidays no longer in the list are disabled. A holiday with departments: "all" applies to every department, including departments added later.
  3. Pushes department contacts to the call-transfer settings and the department contact registry. Custom departments left out of a sent departments list are deleted, and their contacts are deactivated.
  4. Pushes department hours to the agent's availability settings.
  5. If sales hours are included, it syncs the rooftop working days. This uses timezone, or the rooftop's stored timezone. A failure in this sync is logged only.
  6. Removes availability hours for deleted custom departments.
  7. Saves departments, holidays and the timezone used on the rooftop configuration. Other rooftop settings are kept.

Leaving out departments leaves departments as they are. Sending an array, even an empty one, replaces the custom departments. Leaving out holidays leaves holidays as they are. Sending an array replaces the holiday set. Built-in departments are never deleted.

The save does not update any checklist task.

Before you call it

  • You need enterpriseId and teamId.

  • Read the current state with Get departments, hours and holidays. Send back full lists so nothing is deleted by mistake.

  • If you send day-by-day sales hours, either send timezone or make sure the rooftop has a timezone saved by Save rooftop details. Otherwise the call returns 400.

  • Authentication: Bearer token of a signed-in console user. It is checked twice: here, and again by the department settings save, which also needs a user ID in the token.

  • Rate limit: Not documented

  • Processing: Synchronous. Waits for every push (30 second limit on the pass-through). Pushes run in sequence and are not rolled back: if a later step fails, the earlier pushes stay applied and the stored configuration is not updated.


Request

Requiredalways sendOptionalcan be left out
Request checklist
  1. Start from the GET response.
  2. Send departments only if you want to change departments, and send the complete list.
  3. Send holidays only if you want to change holidays, and send the complete list.
  4. Use isSameAsSales / isSameAsService on built-in departments and sameAs on custom ones.
  5. The save does not mark the checklist task. See the Rooftop Setup introduction.
ParameterTypeRequiredDescription
Headers——Sent as HTTP headers.
AuthorizationstringRequiredBearer YOUR_TOKEN
Content-TypestringRequiredapplication/json
Body——Sent as a JSON body.
enterpriseIdstringRequiredDealer group ID.
teamIdstringRequiredRooftop ID.
enterpriseNamestringOptionalStored on the configuration record.
teamNamestringOptionalStored on the configuration record.
timezonestringOptionalIANA timezone used for the sales working-days sync.
departmentsarrayOptionalComplete department list. Leave it out to keep departments as they are.
departments[].namestringRequiredsales, service, parts, finance, or a custom name.
departments[].contactobjectOptionalname (required), phone (required), email (valid email), isIvr (default false), extension, and the six transfer_* booleans.
departments[].timingsobjectOptionalEither all seven days (monday…sunday), each {isAvailable (required), startTime, endTime, isTransferAvailable (default true), weekOverrides}, or a copy marker.
departments[].timings.isSameAsSalesbooleanOptionalBuilt-in only, and not on sales.
departments[].timings.isSameAsServicebooleanOptionalBuilt-in only, and not on sales or service. Use only one of the two flags.
departments[].timings.sameAsstringOptionalCustom departments only. The name of the department to copy.
departments[].addressanyOptionalAddress object, or {sameAs: "<department name or 'rooftop address'>"}.
holidaysarrayOptionalComplete holiday list. Leave it out to keep holidays as they are.
holidays[].namestringRequiredHoliday name.
holidays[].reasonstringRequiredReason.
holidays[].datestringRequiredDate.
holidays[].recurrencestring or nullOptionalmonthly or yearly.
holidays[].openbooleanRequiredtrue if open with special hours.
holidays[].hoursarrayOptional{start, end} windows. Defaults to [].
holidays[].departments"all" or string[]Required"all", or at least one department name.

Sample request

curl -X POST "https://api.spyne.ai/console/v1/product-onboarding/vini/departments" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enterpriseId": "<enterpriseId>",
    "teamId": "<teamId>",
    "timezone": "America/Chicago",
    "departments": [
      {
        "name": "sales",
        "contact": { "name": "Sales", "phone": "+15550100000", "isIvr": false },
        "timings": {
          "monday": { "isAvailable": true, "startTime": "09:00", "endTime": "18:00" },
          "tuesday": { "isAvailable": true, "startTime": "09:00", "endTime": "18:00" },
          "wednesday": { "isAvailable": true, "startTime": "09:00", "endTime": "18:00" },
          "thursday": { "isAvailable": true, "startTime": "09:00", "endTime": "18:00" },
          "friday": { "isAvailable": true, "startTime": "09:00", "endTime": "18:00" },
          "saturday": { "isAvailable": true, "startTime": "10:00", "endTime": "16:00" },
          "sunday": { "isAvailable": false }
        }
      },
      { "name": "service", "timings": { "isSameAsSales": true } }
    ],
    "holidays": [
      { "name": "Thanksgiving", "reason": "Public holiday", "date": "2026-11-26", "recurrence": "yearly", "open": false, "hours": [], "departments": "all" }
    ]
  }'
import requests

day = lambda start, end: {"isAvailable": True, "startTime": start, "endTime": end}
payload = {
    "enterpriseId": "<enterpriseId>",
    "teamId": "<teamId>",
    "timezone": "America/Chicago",
    "departments": [
        {
            "name": "sales",
            "contact": {"name": "Sales", "phone": "+15550100000", "isIvr": False},
            "timings": {
                "monday": day("09:00", "18:00"), "tuesday": day("09:00", "18:00"),
                "wednesday": day("09:00", "18:00"), "thursday": day("09:00", "18:00"),
                "friday": day("09:00", "18:00"), "saturday": day("10:00", "16:00"),
                "sunday": {"isAvailable": False},
            },
        },
        {"name": "service", "timings": {"isSameAsSales": True}},
    ],
    "holidays": [
        {"name": "Thanksgiving", "reason": "Public holiday", "date": "2026-11-26",
         "recurrence": "yearly", "open": False, "hours": [], "departments": "all"}
    ],
}
res = requests.post(
    "https://api.spyne.ai/console/v1/product-onboarding/vini/departments",
    json=payload,
    headers={"Authorization": "Bearer YOUR_TOKEN"},
)
print(res.status_code, res.json())
const day = (startTime, endTime) => ({ isAvailable: true, startTime, endTime });
const res = await fetch("https://api.spyne.ai/console/v1/product-onboarding/vini/departments", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_TOKEN", "Content-Type": "application/json" },
  body: JSON.stringify({
    enterpriseId: "<enterpriseId>",
    teamId: "<teamId>",
    timezone: "America/Chicago",
    departments: [
      {
        name: "sales",
        contact: { name: "Sales", phone: "+15550100000", isIvr: false },
        timings: {
          monday: day("09:00", "18:00"), tuesday: day("09:00", "18:00"), wednesday: day("09:00", "18:00"),
          thursday: day("09:00", "18:00"), friday: day("09:00", "18:00"), saturday: day("10:00", "16:00"),
          sunday: { isAvailable: false },
        },
      },
      { name: "service", timings: { isSameAsSales: true } },
    ],
    holidays: [
      { name: "Thanksgiving", reason: "Public holiday", date: "2026-11-26", recurrence: "yearly", open: false, hours: [], departments: "all" },
    ],
  }),
});
console.log(res.status, await res.json());

Sample response

{ "success": true, "message": "Departments configured successfully" }
{
  "success": false,
  "message": "Validation error",
  "errors": [{ "code": "custom", "path": ["departments", 1, "timings"], "message": "service supports only isSameAsSales" }]
}
{ "success": false, "message": "timezone is required", "error": "timezone is required" }
{ "message": "Invalid Token", "error": true, "code": "ERROR_AUTH_401", "details": "", "data": null }
{ "status": "401", "message": "Invalid Auth key" }
{ "message": "...", "error": true, "code": "ERROR_REQ_TIMEOUT_408", "details": "", "data": null }
{ "success": false, "message": "Failed to create Vini departments", "error": "Error creating holidays for departments" }
{ "message": "No response received from external API", "error": "timeout of 30000ms exceeded" }

400 Bad Request (rule checks). Other messages with the same shape:

  • Circular sameAs reference for work shift timings involving department "<name>"
  • Circular sameAs reference for address involving department "<name>"
  • Cannot copy work shift timings for department "<name>": source department "<source>" has no work shift timings

Response fields

ParameterTypeDescription
successbooleantrue on 201.
messagestringDepartments configured successfully.

Errors

StatusReasonWhen it happens
400Validation errorBody fails the schema. Examples: missing enterpriseId/teamId, bad email, a holiday without departments, sameAs on a built-in department, both copy flags set, sales copying another department.
400timezone is requiredSales day-by-day hours sent, with no timezone and no stored rooftop timezone.
400Circular sameAs / Cannot copy work shift timingsA copy marker loops, or points at a department with no hours.
401ERROR_AUTH_401 / Invalid Auth key / User ID not found in tokenToken missing or invalid, or no user ID in it.
408ERROR_REQ_TIMEOUT_408Console token check could not reach the auth service.
500Failed to create Vini departmentsA push failed. error names which one: holidays, contacts, working hours, or deleting working hours for removed departments. Earlier pushes stay applied.
500No response received from external API / Error setting up requestThe department settings save did not answer in 30 seconds, or the request could not be sent.

Next

Re-read with Get departments, hours and holidays to confirm. The save does not complete the "Department Details & Holidays" checklist task (see the Rooftop Setup introduction). Employee Directory uses the departments saved here for its department dropdown.


Did this page help you?