ExoVoIPDeveloper guide

Business hours

Calendars define when the company is open: weekly time slots, holidays, exceptions (special closures or openings) and manual overrides. Numbers, routes, menus and queues can follow a calendar. Scopes calendars:read / calendars:write.

Creating a calendar

curl -s -X POST https://centralino.exovoip.it/api/v1/calendars \
  -H "X-API-Key: $EXOPBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Ufficio","timezone":"Europe/Rome","isDefault":true,
       "closedDestination":{"type":"voicemail","extensionId":12},
       "hours":[{"weekday":1,"start":"09:00","end":"13:00"},{"weekday":1,"start":"14:00","end":"18:00"}],
       "preloadHolidays":true}'
  • hours: time slots per weekday (weekday from 1 = Monday to 7 = Sunday, times as HH:MM, 24:00 for end of day). Multiple slots on the same day are allowed. PUT /v1/calendars/:id/hours replaces all slots.
  • openDestination / closedDestination: where calls go during and outside business hours (used by the calendar destination). closedPromptId plays a prompt before the closed destination.
  • isDefault: the tenant's default calendar, used by feature codes *90–*93.
  • preloadHolidays: loads national holidays; POST /v1/calendars/:id/holidays can also add the local patron saint's day for the municipality (ISTAT code).

Forcing open or closed

An override takes precedence over business hours and exceptions. Use it for sudden closures (stocktaking, emergencies) or special openings.

# Chiuso per 2 ore
curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/force \
  -H "X-API-Key: $EXOPBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"state":"closed","mode":"hours","hours":2,"note":"Inventario"}'
# Stato attuale
curl -s https://centralino.exovoip.it/api/v1/calendars/4/status -H "X-API-Key: $EXOPBX_API_KEY"
# Ritorno agli orari normali
curl -s -X DELETE https://centralino.exovoip.it/api/v1/calendars/4/force -H "X-API-Key: $EXOPBX_API_KEY"

Expiry modes (mode):

modeDuration
next_transitionUntil the next change scheduled by the business hours. For a forced closure: until the next scheduled opening (e.g. from Friday evening to Monday morning). Default.
hoursFor hours hours (1–720)
untilUntil the date and time in until
manualUntil removed with DELETE /v1/calendars/:id/force
# Aperto fino alla prossima variazione prevista dagli orari
curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/force -H "X-API-Key: $EXOPBX_API_KEY" \
  -H "Content-Type: application/json" -d '{"state":"open","mode":"next_transition"}'
# Chiuso fino a una data e ora precise
curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/force -H "X-API-Key: $EXOPBX_API_KEY" \
  -H "Content-Type: application/json" -d '{"state":"closed","mode":"until","until":"2026-12-27T08:00:00.000Z"}'
# Chiuso finché non viene rimossa la forzatura
curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/force -H "X-API-Key: $EXOPBX_API_KEY" \
  -H "Content-Type: application/json" -d '{"state":"closed","mode":"manual"}'

GET /v1/calendars/:id/status returns the current status (open / closed), the reason (force, exception, weekly, no_hours), the next change and any active override. The override history (from the control panel, API or phone) is at GET /v1/calendars/:id/overrides.

Each override generates the calendar.override real-time event (also delivered to webhooks) and, if configured, a notification.

From the phone: enabled extensions use *90 (closed), *91 (open), *92 (restore business hours) and *93 (status), with an optional PIN. See Extensions. Each extension can also follow a company calendar and switch itself off or on with *94 / *95: see Extension hours and status.

Exceptions and simulation

Exceptions cover periods with different hours: vacations, long weekends, special openings. The simulator returns the calendar status at any given moment, with details for that day.

curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/exceptions \
  -H "X-API-Key: $EXOPBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Chiusura estiva","type":"closed","dateFrom":"2026-08-10","dateTo":"2026-08-21"}'
curl -s -X POST https://centralino.exovoip.it/api/v1/calendars/4/simulate \
  -H "X-API-Key: $EXOPBX_API_KEY" -H "Content-Type: application/json" -d '{"at":"2026-08-12T10:00:00+02:00"}'

iCal (.ics) import and export: POST /v1/calendars/:id/ical/import (text or URL), GET /v1/calendars/:id/ical/export.ics; with icalUrl set, synchronization runs periodically (POST /v1/calendars/:id/ical/sync to force it).

Linking a number

curl -s -X PUT https://centralino.exovoip.it/api/v1/numbers/7/calendar \
  -H "X-API-Key: $EXOPBX_API_KEY" -H "Content-Type: application/json" \
  -d '{"calendarId":4,"closedDestination":{"type":"voicemail","extensionId":12}}'

Endpoints

RequestScopeSDK method
GET /v1/calendarscalendars:readcalendars.list()
POST /v1/calendarscalendars:writecalendars.create()
GET /v1/calendars/holidayscalendars:readcalendars.holidays()
GET /v1/calendars/:idcalendars:readcalendars.get()
PATCH /v1/calendars/:idcalendars:writecalendars.update()
DELETE /v1/calendars/:idcalendars:writecalendars.delete()
PUT /v1/calendars/:id/hourscalendars:writecalendars.setHours() · py: calendars.set_hours()
GET /v1/calendars/:id/statuscalendars:readcalendars.status()
POST /v1/calendars/:id/forcecalendars:writecalendars.force()
DELETE /v1/calendars/:id/forcecalendars:writecalendars.clearForce() · py: calendars.clear_force()
GET /v1/calendars/:id/overridescalendars:readcalendars.overrides()
POST /v1/calendars/:id/simulatecalendars:readcalendars.simulate()
POST /v1/calendars/:id/holidayscalendars:writecalendars.preloadHolidays() · py: calendars.preload_holidays()
GET /v1/calendars/:id/exceptionscalendars:readcalendars.listExceptions() · py: calendars.list_exceptions()
POST /v1/calendars/:id/exceptionscalendars:writecalendars.createException() · py: calendars.create_exception()
PATCH /v1/calendars/:id/exceptions/:exceptionIdcalendars:writecalendars.updateException() · py: calendars.update_exception()
DELETE /v1/calendars/:id/exceptions/:exceptionIdcalendars:writecalendars.deleteException() · py: calendars.delete_exception()
POST /v1/calendars/:id/ical/importcalendars:writecalendars.importIcal() · py: calendars.import_ical()
GET /v1/calendars/:id/ical/export.icscalendars:readcalendars.exportIcal() · py: calendars.export_ical()
POST /v1/calendars/:id/ical/synccalendars:writecalendars.syncIcal() · py: calendars.sync_ical()