/** * SpokService — main library class for the Spok SmartSuite TCP API. * * Usage: * const SpokService = require("spok-api"); * const service = new SpokService({ host: "spok.example.com", port: 5000, ssl: true }); * const listing = await service.getListingInfo("308787"); */ import { SpokServiceOptions, SpokResponse } from "./types"; import { amcomRequestWithFailover } from "./client"; // Re-export everything consumers might need export { SpokServiceOptions, SpokResponse, AmcomHeader } from "./types"; export { buildRequestXml, parseResponseXml, parseXmlToObject, parseChildrenToObject, escapeXml, unescapeXml, REQUEST_NS, } from "./xml"; export { amcomRequest, amcomRequestWithFailover, buildHeader, parseHeader, API_VERSION, REFERENCE_ID, MIN_BODY_SIZE, HEADER_SIZE, DEFAULT_TIMEOUT, } from "./client"; /** * Custom error class for Spok API errors. */ class SpokError extends Error { code: string | null; method: string; constructor(message: string, method: string, code?: string | null) { super(message); this.name = "SpokError"; this.method = method; this.code = code || null; } } /** * Main service class for the Spok SmartSuite TCP API. * Wraps the low-level TCP protocol with typed, named methods. */ class SpokService { private hosts: string[]; private port: number; private ssl: boolean; private insecure: boolean; private debug: boolean; private timeout: number; constructor(opts: SpokServiceOptions) { this.hosts = [opts.host]; if (opts.hostFailover) this.hosts.push(opts.hostFailover); this.port = opts.port; this.ssl = opts.ssl || false; this.insecure = opts.insecure || false; this.debug = opts.debug || false; this.timeout = opts.timeout || 60000; } /** * Execute an arbitrary Amcom API method. * This is the foundation — all named methods delegate to this. */ async execute(method: string, params?: Record): Promise { return amcomRequestWithFailover( this.hosts, this.port, method, params, this.ssl, this.insecure, this.debug, this.timeout ); } // ─── Listings ────────────────────────────────────────────────────────────── /** Get listing info by listing ID. */ async getListingInfo(lid: string): Promise { return this.execute("GetListingInfo", { lid }); } /** Get listing info by messaging ID. */ async getListingInfoByMid(mid: string): Promise { return this.execute("GetListingInfoByMid", { mid }); } /** Search listings by name. */ async getListingsByName(name: string, searchType?: string, midFlag?: string): Promise { const params: Record = { name }; if (searchType) params.search_type = searchType; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsByName", params); } /** Get listings by employee ID. */ async getListingsByEid(eid: string, midFlag?: string): Promise { const params: Record = { eid }; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsByEid", params); } /** Get listings by SSN. */ async getListingsBySsn(ssn: string, midFlag?: string): Promise { const params: Record = { ssn }; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsBySsn", params); } /** Get listings by user-defined field. */ async getListingsByUdf(udfCol: string, udf: string, midFlag?: string): Promise { const params: Record = { udf_col: udfCol, udf }; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsByUdf", params); } /** Get listings by data-feed ID. */ async getListingsByFeedId(fid: string, midFlag?: string): Promise { const params: Record = { fid }; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsByFeedId", params); } // ─── SSO / Messaging ID ─────────────────────────────────────────────────── /** Get SSO username by messaging ID. */ async getSSOUsername(mid: string): Promise { return this.execute("GetSSOUsername", { mid }); } /** Get messaging ID by SSO username. */ async getMessagingID(ssoUsername: string): Promise { return this.execute("GetMessagingID", { sso_username: ssoUsername }); } /** Assign a messaging ID to a listing. */ async assignMessagingId(lid: string): Promise { return this.execute("AssignMessagingId", { lid }); } // ─── Pagers ──────────────────────────────────────────────────────────────── /** Get pager ID(s) by messaging ID. */ async getPagerId(mid: string): Promise { return this.execute("GetPagerId", { mid }); } /** Get pager info by pager ID. */ async getPagerInfo(pid: string): Promise { return this.execute("GetPagerInfo", { pid }); } /** Get pager info by messaging ID. */ async getPagerInfoByMid(mid: string): Promise { return this.execute("GetPagerInfoByMID", { mid }); } /** Add a new pager. */ async addPager(params: Record): Promise { return this.execute("AddPager", params); } /** Assign a pager to a messaging ID. */ async assignPager(mid: string, pagerId: string, displayOrder: string): Promise { return this.execute("AssignPager", { mid, pager_id: pagerId, display_order: displayOrder }); } /** Delete a pager by pager ID. */ async deletePager(pid: string): Promise { return this.execute("DeletePager", { pid }); } // ─── Email ───────────────────────────────────────────────────────────────── /** Get email address by messaging ID. */ async getEmailAddress(mid: string): Promise { return this.execute("GetEmailAddress", { mid }); } /** Add email address by messaging ID. */ async addEmailAddress(mid: string, emailAddress: string, displayOrder: string): Promise { return this.execute("AddEmailAddress", { mid, email_address: emailAddress, display_order: displayOrder }); } /** Add email address by listing ID. */ async addEmailAddressByLid(lid: string, emaddr: string, dorder?: string): Promise { const params: Record = { lid, emaddr }; if (dorder) params.dorder = dorder; return this.execute("AddEmailAddressByLid", params); } // ─── Directories ─────────────────────────────────────────────────────────── /** Get listing directories by listing ID. */ async getListingDirectories(lid: string, phtype?: string): Promise { const params: Record = { lid }; if (phtype) params.phtype = phtype; return this.execute("GetListingDirectories", params); } /** Get directory info by directory sequence number. */ async getDirectoryInfo(dirseq: string): Promise { return this.execute("GetDirectoryInfo", { dirseq }); } /** Add a listing directory entry. */ async addListingDirectory(params: Record): Promise { return this.execute("AddListingDirectory", params); } /** Update a directory entry. */ async updateDirectory(params: Record): Promise { return this.execute("UpdateDirectory", params); } /** Delete a listing directory entry. */ async deleteListingDirectory(lid: string, dirseq: string): Promise { return this.execute("DeleteListingDirectory", { lid, dirseq }); } /** Set directory enabled flag. */ async setDirectoryEnabled(dirseq: string, module: string, eflag: string): Promise { return this.execute("SetDirectoryEnabled", { dirseq, module, eflag }); } /** Set directory published flag. */ async setDirectoryPublished(dirseq: string, module: string, pflag: string): Promise { return this.execute("SetDirectoryPublished", { dirseq, module, pflag }); } /** Set directory transfer-allowed flag. */ async setDirectoryTransferAllowed(dirseq: string, module: string, taflag: string): Promise { return this.execute("SetDirectoryTransferAllowed", { dirseq, module, taflag }); } // ─── Persons ─────────────────────────────────────────────────────────────── /** Add a new person listing. */ async addPerson(params: Record): Promise { return this.execute("AddPerson", params); } /** Update an existing person listing. */ async updatePerson(params: Record): Promise { return this.execute("UpdatePerson", params); } // ─── Status & Paging ─────────────────────────────────────────────────────── /** Change a listing's status code and text. */ async changeStatus(mid: string, statusCode: string, statusText: string): Promise { return this.execute("ChangeStatus", { mid, status_code: statusCode, status_text: statusText }); } /** Send a page to a messaging ID. */ async sendPage(mid: string, pagedText: string, priority?: string): Promise { const params: Record = { mid, paged_text: pagedText }; if (priority) params.priority = priority; return this.execute("SendPage", params); } // ─── Groups ──────────────────────────────────────────────────────────────── /** Get message group members. */ async getMessageGroupMembers(reqlid: string, grpnum: string): Promise { return this.execute("GetMessageGroupMembers", { reqlid, grpnum }); } /** Add a member to an on-call group. */ async addOncallGroupMember(oncallMid: string, mid: string): Promise { return this.execute("AddOncallGroupMember", { oncall_mid: oncallMid, mid }); } /** Add a member to a static message group. */ async addStaticMessageGroupMember(params: Record): Promise { return this.execute("AddStaticMessageGroupMember", params); } // ─── On-call Assignments ─────────────────────────────────────────────────── /** Get current on-call assignments by group. */ async getGroupsCurrentAssignments(groupMid: string): Promise { return this.execute("GetGroupsCurrentAssignments", { group_mid: groupMid }); } /** Get all on-call assignments by group. */ async getGroupsAssignments(groupMid: string): Promise { return this.execute("GetGroupsAssignments", { group_mid: groupMid }); } /** Get current on-call assignments by messaging ID. */ async getIdsCurrentAssignments(mid: string): Promise { return this.execute("GetIdsCurrentAssignments", { mid }); } /** Get all on-call assignments by messaging ID. */ async getIdsAssignments( mid: string, startDate: string, endDate: string, timezone: string ): Promise { return this.execute("GetIdsAssignments", { mid, start_date: startDate, end_date: endDate, timezone, }); } /** Get current on-call assignment with exceptions by group name. */ async getCurrentAssignmentWithExceptions(name: string): Promise { return this.execute("GetCurrentAssignmentWithExceptions", { name }); } /** Get current assignment listing IDs by group name. */ async getCurrentAssignmentLids(name: string): Promise { return this.execute("GetCurrentAssignmentLids", { name }); } /** Get on-call group roles. */ async getOncallGroupRoles(): Promise { return this.execute("GetOncallGroupRoles"); } /** Get current group assignments as XML (with timezone). */ async getGroupsCurrAssignXml(ocmid: string, tz: string): Promise { return this.execute("GetGroupsCurrAssignXml", { ocmid, tz }); } /** Get group assignments XML for a date range. */ async getGroupsAssignmentsXml(ocmid: string, ocastart: string, ocaend: string, tz: string): Promise { return this.execute("GetGroupsAssignmentsXml", { ocmid, ocastart, ocaend, tz }); } // ─── Exceptions & Coverage ───────────────────────────────────────────────── /** Get current exception by messaging ID. */ async getCurrentException(mid: string): Promise { return this.execute("GetCurrentException", { mid }); } /** Get all exceptions by messaging ID. */ async getExceptions(mid: string): Promise { return this.execute("GetExceptions", { mid }); } /** Get exception list by messaging ID. */ async getExceptionList(mid: string): Promise { return this.execute("GetExceptionList", { mid }); } /** Get coverage path by messaging ID. */ async getCoveragePath(mid: string): Promise { return this.execute("GetCoveragePath", { mid }); } /** Get final covering messaging ID. */ async getFinalCoveringId(mid: string): Promise { return this.execute("GetFinalCoveringId", { mid }); } /** Get final covering person details. */ async getFinalCoveringPerson(mid: string): Promise { return this.execute("GetFinalCoveringPerson", { mid }); } // ─── Reference Data ──────────────────────────────────────────────────────── /** Get all organization codes. */ async getOrgCodes(): Promise { return this.execute("GetOrgCodes"); } /** Get all phone number types. */ async getPhoneNumberTypes(): Promise { return this.execute("GetPhoneNumberTypes"); } /** Get all buildings. */ async getAllBuildings(): Promise { return this.execute("GetAllBuildings"); } /** Get all titles. */ async getTitles(): Promise { return this.execute("GetTitles"); } // ─── High-priority CLOB reads ────────────────────────────────────────────── /** * Search listings by last name (CLOB output — bulk-safe). * @param searchType required by the server — one of EXACT, BEGINS WITH, ENDS WITH, CONTAINS. */ async getListingsByLastName(lname: string, searchType: string, midFlag?: string): Promise { const params: Record = { lname, search_type: searchType }; if (midFlag) params.mid_flag = midFlag; return this.execute("GetListingsByLastName", params); } /** * Get directories by UDF column with search type (CLOB output — bulk-safe). * @param lid optional — restrict search to a listing ID (amcomapi.xml `lid`, nullable="true"). * @param phtype optional — phone type filter (amcomapi.xml `phtype`, nullable="true"). */ async getDirectoriesByUdf( udfCol: string, udf: string, searchType?: string, lid?: string, phtype?: string ): Promise { const params: Record = { udf_col: udfCol, udf }; if (searchType) params.search_type = searchType; if (lid) params.lid = lid; if (phtype) params.phtype = phtype; return this.execute("GetDirectoriesByUdf", params); } /** Get full department list. */ async getAllDepartments(): Promise { return this.execute("GetAllDepartments"); } /** Get hierarchical department tree by directory sequence number. */ async getDepartmentHierarchy(dirseq: string): Promise { return this.execute("GetDepartmentHierarchy", { dirseq }); } /** Get full address list. */ async getAllAddresses(): Promise { return this.execute("GetAllAddresses"); } /** * Get message groups visible to a requesting listing. * @param reqlid required — the requesting operator's listing ID. */ async getMessageGroups(reqlid: string): Promise { return this.execute("GetMessageGroups", { reqlid }); } /** Get pager info keyed by listing ID. */ async getPagerInfoByLid(lid: string): Promise { return this.execute("GetPagerInfoByLid", { lid }); } /** Get record name by listing ID. */ async getRecordNameByLid(lid: string): Promise { return this.execute("GetRecordNameByLid", { lid }); } /** Get record name by messaging ID. */ async getRecordNameByMid(mid: string): Promise { return this.execute("GetRecordNameByMid", { mid }); } /** Get record name by pager ID. */ async getRecordNameByPid(pid: string): Promise { return this.execute("GetRecordNameByPid", { pid }); } /** Get record name only by messaging ID (fastest name-only lookup). */ async getRecordNameOnlyByMid(mid: string): Promise { return this.execute("GetRecordNameOnlyByMid", { mid }); } /** Get listing instruction notes by listing ID. */ async getListingInstructions(lid: string): Promise { return this.execute("GetListingInstructions", { lid }); } /** Get instruction info by instruction sequence number. */ async getInstructionInfo(seqnum: string): Promise { return this.execute("GetInstructionInfo", { seqnum }); } /** Get a shared listing instruction by instruction sequence number. */ async getSharedListingInstruction(seqnum: string): Promise { return this.execute("GetSharedListingInstruction", { seqnum }); } /** Get status code reference table. */ async getStatusCodes(): Promise { return this.execute("GetStatusCodes"); } /** * Get paging info by name or messaging ID. * All three params are optional per amcomapi.xml (`lname`, `fname`, `mid` all nullable="true"); * callers should supply at least one to get a useful result. * @param mid optional — messaging ID. * @param lname optional — last name. * @param fname optional — first name. */ async getPagingInfo(mid?: string, lname?: string, fname?: string): Promise { const params: Record = {}; if (lname) params.lname = lname; if (fname) params.fname = fname; if (mid) params.mid = mid; return this.execute("GetPagingInfo", params); } /** Get pager carrier/COS list. */ async getPagerCoses(): Promise { return this.execute("GetPagerCoses"); } /** Get pager model list. */ async getPagerModels(): Promise { return this.execute("GetPagerModels"); } /** * Get currently-active notifications visible to a requesting listing. * @param rlid required — the requesting operator's listing ID. */ async getActiveNotifications(rlid: string): Promise { return this.execute("GetActiveNotifications", { rlid }); } /** * Get all event templates visible to a requesting listing. * @param reqlid required — the requesting operator's listing ID. */ async getAllEventTemplates(reqlid: string): Promise { return this.execute("GetAllEventTemplates", { reqlid }); } /** * Get event template detail. * @param reqlid required — the requesting operator's listing ID. * @param evid required — the event template ID. */ async getEventTemplateDetail(reqlid: string, evid: string): Promise { return this.execute("GetEventTemplateDetail", { reqlid, evid }); } /** * Get event activations visible to a requesting listing. * @param reqlid required — the requesting operator's listing ID. * @param ssflag optional — start/stop flag filter. * @param actdate optional — activation date filter. */ async getEventActivations( reqlid: string, ssflag?: string, actdate?: string ): Promise { const params: Record = { reqlid }; if (ssflag) params.ssflag = ssflag; if (actdate) params.actdate = actdate; return this.execute("GetEventActivations", params); } /** * Get event activation detail. * @param reqlid required — the requesting operator's listing ID. * @param evrseq required — the event activation (response) sequence number. */ async getEventActivationDetail(reqlid: string, evrseq: string): Promise { return this.execute("GetEventActivationDetail", { reqlid, evrseq }); } /** Get on-call assignments for a messaging ID as XML. */ async getIdsAssignmentsXml( mid: string, ocastart: string, ocaend: string, tz: string ): Promise { return this.execute("GetIdsAssignmentsXml", { mid, ocastart, ocaend, tz }); } /** Get current on-call assignment for a messaging ID as XML. */ async getIdsCurrAssignXml(mid: string, tz: string): Promise { return this.execute("GetIdsCurrAssignXml", { mid, tz }); } // ─── Additional reads (contacts, devices, status) ────────────────────────── /** Get all email addresses by listing ID. */ async getEmailAddresses(lid: string): Promise { return this.execute("GetEmailAddresses", { lid }); } /** Get email address by listing ID. */ async getEmailAddressByLid(lid: string): Promise { return this.execute("GetEmailAddressByLid", { lid }); } /** Get email address by listing ID and display order. */ async getEmailAddressByOrder(lid: string, dorder: string): Promise { return this.execute("GetEmailAddressByOrder", { lid, dorder }); } /** Get email address(es) by caller ID. */ async getCallerEmailAddress(cid: string): Promise { return this.execute("GetCallerEmailAddress", { cid }); } /** Get alternate phone by messaging ID. */ async getAlternatePhone(mid: string): Promise { return this.execute("GetAlternatePhone", { mid }); } /** * Get phone number(s) of a specified user. * @param mid required — messaging ID of the user. * @param phoneNumberType optional — a specific phone number type to filter to. */ async getPhoneNumber(mid: string, phoneNumberType?: string): Promise { const params: Record = { mid }; if (phoneNumberType) params.phone_number_type = phoneNumberType; return this.execute("GetPhoneNumber", params); } /** * Get phone number(s) of a specified user using listing_id. * @param lid required — listing ID of the user. * @param phoneNumberType optional — a specific phone number type to filter to. */ async getPhoneNumberByLid(lid: string, phoneNumberType?: string): Promise { const params: Record = { lid }; if (phoneNumberType) params.phone_number_type = phoneNumberType; return this.execute("GetPhoneNumberByLid", params); } /** Get address type reference list. */ async getAddressTypes(): Promise { return this.execute("GetAddressTypes"); } /** Get directory type reference list. */ async getDirectoryTypes(): Promise { return this.execute("GetDirectoryTypes"); } /** * Get profile specialties for a listing. * @param irFid required — the listing/feed ID to look up specialties for. */ async getProfileSpecialties(irFid: string): Promise { return this.execute("GetProfileSpecialties", { ir_fid: irFid }); } /** * Get assigned contact devices for a listing. * @param lid required — the listing ID. * @param cltype required — the contact list type: "ON HOURS" or "OFF HOURS". */ async getAssignedContactDevices(lid: string, cltype: string): Promise { return this.execute("GetAssignedContactDevices", { lid, cltype }); } /** * Get unassigned contact devices for a listing. * @param lid required — the listing ID. * @param cltype required — the contact list type: "ON HOURS" or "OFF HOURS". */ async getUnassignedContactDevices(lid: string, cltype: string): Promise { return this.execute("GetUnassignedContactDevices", { lid, cltype }); } /** Get page routes reference list. */ async getPageRoutes(): Promise { return this.execute("GetPageRoutes"); } /** Check whether a directory sequence number belongs to a pager. */ async isPagerByDirectorySeqnum(dirseq: string): Promise { return this.execute("IsPagerByDirectorySeqnum", { dirseq }); } /** * Check whether a listing ID + phone number combination belongs to a pager. * @param lid required — the listing ID. * @param phnum required — the phone number to check. */ async isPagerByListingId(lid: string, phnum: string): Promise { return this.execute("IsPagerByListingId", { lid, phnum }); } /** Check whether a phone number belongs to a pager. */ async isPagerByPhone(phnum: string): Promise { return this.execute("IsPagerByPhone", { phnum }); } /** Get current status by messaging ID. */ async getStatus(mid: string): Promise { return this.execute("GetStatus", { mid }); } /** Get ID status by messaging ID. */ async getIdStatus(mid: string): Promise { return this.execute("GetIdStatus", { mid }); } /** Get statuses by employee ID. */ async getStatusesByEid(eid: string): Promise { return this.execute("GetStatusesByEid", { eid }); } /** Get statuses by feed ID. */ async getStatusesByFeedId(fid: string): Promise { return this.execute("GetStatusesByFeedId", { fid }); } /** * Get statuses by last name. * @param searchType required — one of EXACT, BEGINS WITH, ENDS WITH, CONTAINS. */ async getStatusesByLastName(lname: string, searchType: string): Promise { return this.execute("GetStatusesByLastName", { lname, search_type: searchType }); } /** Get statuses updated on or after a date (YYYY-MM-DD). */ async getStatusesByLatestDate(date: string): Promise { return this.execute("GetStatusesByLatestDate", { date }); } /** * Get statuses by name. * @param searchType required — one of EXACT, BEGINS WITH, ENDS WITH, CONTAINS. */ async getStatusesByName(name: string, searchType: string): Promise { return this.execute("GetStatusesByName", { name, search_type: searchType }); } /** Get statuses by SSN. */ async getStatusesBySsn(ssn: string): Promise { return this.execute("GetStatusesBySsn", { ssn }); } /** Get statuses by user-defined field. */ async getStatusesByUdf(udfCol: string, udf: string): Promise { return this.execute("GetStatusesByUdf", { udf_col: udfCol, udf }); } /** Get work hours by listing ID. */ async getWorkHours(lid: string): Promise { return this.execute("GetWorkHours", { lid }); } /** * Get the status of a notification step. * @param stepseq required — the notification step sequence number. */ async getNotificationStatus(stepseq: string): Promise { return this.execute("GetNotificationStatus", { stepseq }); } /** * Get the queries run for a notification step. * @param rlid required — the requesting operator's listing ID. * @param stepseq required — the notification step sequence number. */ async getNotificationStepQueries(rlid: string, stepseq: string): Promise { return this.execute("GetNotificationStepQueries", { rlid, stepseq }); } /** * Get the current status of an activated event. * @param requestSeqnum required — sequence number of the event whose status is returned. */ async getEventStatus(requestSeqnum: string): Promise { return this.execute("GetEventStatus", { request_seqnum: requestSeqnum }); } /** * Get event template privilege. * @param reqlid required — the requesting operator's listing ID. * @param evid required — the event template ID. */ async getEventTemplatePrivilege(reqlid: string, evid: string): Promise { return this.execute("GetEventTemplatePrivilege", { reqlid, evid }); } /** * Get recipient count for an event activation. * @param reqlid required — the requesting operator's listing ID. * @param evrseq required — the event activation (response) sequence number. */ async getActivationRecipientCount(reqlid: string, evrseq: string): Promise { return this.execute("GetActivationRecipientCount", { reqlid, evrseq }); } /** * Get recipient count for an event template. * @param reqlid required — the requesting operator's listing ID. * @param evid required — the event template ID. */ async getTemplateRecipientCount(reqlid: string, evid: string): Promise { return this.execute("GetTemplateRecipientCount", { reqlid, evid }); } /** * Get query template info. * @param reqlid required — the requesting operator's listing ID. * @param qseq required — the query sequence number. */ async getQueryTemplateInfo(reqlid: string, qseq: string): Promise { return this.execute("GetQueryTemplateInfo", { reqlid, qseq }); } // ─── Monitoring ──────────────────────────────────────────────────────────── /** Get event detail for a monitored event. */ async monitorEventDetail(params: Record): Promise { return this.execute("MonitorEventDetail", params); } /** Get event status for a monitored event. */ async monitorEventStatus(params: Record): Promise { return this.execute("MonitorEventStatus", params); } /** Get event status summary for a monitored event. */ async monitorEventStatusSummary(params: Record): Promise { return this.execute("MonitorEventStatusSummary", params); } /** Get procedure status summary for a monitored event. */ async monitorProcStatusSummary(params: Record): Promise { return this.execute("MonitorProcStatusSummary", params); } /** Get step responses for a monitored event. */ async monitorStepResponses(params: Record): Promise { return this.execute("MonitorStepResponses", params); } /** Get step status summary for a monitored event. */ async monitorStepStatusSummary(params: Record): Promise { return this.execute("MonitorStepStatusSummary", params); } // ─── Writes — people, listings, devices ─────────────────────────────────── /** Delete a person listing by listing ID. */ async deletePerson(lid: string): Promise { return this.execute("DeletePerson", { lid }); } /** Enable or disable a listing for a given module. */ async setListingEnabled(lid: string, module: string, eflag: string): Promise { return this.execute("SetListingEnabled", { lid, module, eflag }); } /** Update the messaging ID on a listing. */ async updateMessagingId(lid: string, mid: string): Promise { return this.execute("UpdateMessagingId", { lid, mid }); } /** Assign a role to a listing. */ async assignRole(lid: string, role: string): Promise { return this.execute("AssignRole", { lid, role }); } /** Assign message priorities to a listing. */ async assignMessagePriorities(params: Record): Promise { return this.execute("AssignMessagePriorities", params); } /** Assign group limits to a listing. */ async assignGroupLimits(params: Record): Promise { return this.execute("AssignGroupLimits", params); } /** Add a phone number to a listing. */ async addPhoneNumber(params: Record): Promise { return this.execute("AddPhoneNumber", params); } /** * Delete a phone number from a listing's directory phone list. * @param lid required — listing ID. * @param phoneNumber optional — phone number to match (per amcomapi.xml `phone_number`, nullable="true"). * @param phoneType optional — phone type to match (per amcomapi.xml `phone_type`, nullable="true"). */ async deleteListingDirectoryPhone(lid: string, phoneNumber?: string, phoneType?: string): Promise { const params: Record = { lid }; if (phoneNumber) params.phone_number = phoneNumber; if (phoneType) params.phone_type = phoneType; return this.execute("DeleteListingDirectoryPhone", params); } /** Delete an email address by listing ID. */ async deleteEmailAddressByLid(lid: string, emaddr: string): Promise { return this.execute("DeleteEmailAddressByLid", { lid, emaddr }); } /** Update an email address by listing ID. */ async updateEmailAddressByLid(lid: string, oldEmaddr: string, newEmaddr: string): Promise { return this.execute("UpdateEmailAddressByLid", { lid, old_emaddr: oldEmaddr, new_emaddr: newEmaddr }); } /** * Assign a pager to a listing by listing ID. * @param lid required — listing ID. * @param pid required — pager ID (per amcomapi.xml `pid`, nullable="false"). * @param dorder optional — display order (per amcomapi.xml `dorder`, nullable="true"). */ async assignPagerByLid(lid: string, pid: string, dorder?: string): Promise { const params: Record = { lid, pid }; if (dorder) params.dorder = dorder; return this.execute("AssignPagerByLid", params); } /** Update pager properties. */ async updatePager(params: Record): Promise { return this.execute("UpdatePager", params); } /** Add a listing instruction note. */ async addListingInstruction(params: Record): Promise { return this.execute("AddListingInstruction", params); } /** Update a listing instruction note. */ async updateListingInstruction(params: Record): Promise { return this.execute("UpdateListingInstruction", params); } /** * Delete a listing instruction by sequence number. * @param seqnum required — the instruction sequence number. * @param lid required — the owning listing ID (server needs both). */ async deleteListingInstruction(seqnum: string, lid: string): Promise { return this.execute("DeleteListingInstruction", { seqnum, lid }); } /** * Share a listing instruction with another listing. * @param seqnum required — the instruction sequence number (the family uses seqnum, not instrseq). * @param targetLid required — the listing ID to share the instruction to (per amcomapi.xml * the wire param is `lid`, same name as the owning-listing param used elsewhere in this * family; here it identifies the *target* of the share). */ async shareListingInstruction(seqnum: string, targetLid: string): Promise { return this.execute("ShareListingInstruction", { seqnum, lid: targetLid }); } /** Change (or create) an exception. */ async changeException(params: Record): Promise { return this.execute("ChangeException", params); } /** * Delete an exception. * @param mid required — messaging ID that owns the exception. * @param exseq required — the exception sequence number to delete. */ async deleteException(mid: string, exseq: string): Promise { return this.execute("DeleteException", { mid, exseq }); } /** * Add a personal contact device. * Required params per amcomapi.xml: lid, cltype, devtype, devid. Optional: dorder. */ async addPersonalContactDevice(params: Record): Promise { return this.execute("AddPersonalContactDevice", params); } /** Update a personal contact device (pdoseq, dorder — both required). */ async updatePersonalContactDevice(params: Record): Promise { return this.execute("UpdatePersonalContactDevice", params); } /** * Delete a personal contact device. * @param pdoseq required — the device sequence number (returned as pdoseq by getAssignedContactDevices). */ async deletePersonalContactDevice(pdoseq: string): Promise { return this.execute("DeletePersonalContactDevice", { pdoseq }); } /** * Delete all personal device options for a listing. * @param lid required — per amcomapi.xml the wire param is `lid`, not `mid` * (live-verified: sending `mid` returns "request does not contain parameter lid"). */ async deleteAllPersonalDeviceOptions(lid: string): Promise { return this.execute("DeleteAllPersonalDeviceOptions", { lid }); } /** Swap the display order of two personal contact devices (pdoseq, dorder — both required). */ async swapPersonalContactDevice(params: Record): Promise { return this.execute("SwapPersonalContactDevice", params); } /** * Unassign all contact devices from a listing. * @param lid required — per amcomapi.xml the wire param is `lid`, not `mid` * (live-verified: sending `mid` returns "request does not contain parameter lid"). */ async unassignContactDevices(lid: string): Promise { return this.execute("UnassignContactDevices", { lid }); } /** Register an AMC device. */ async registerAMCDevice(params: Record): Promise { return this.execute("RegisterAMCDevice", params); } /** Unregister an AMC device. */ async unregisterAMCDevice(params: Record): Promise { return this.execute("UnregisterAMCDevice", params); } // ─── Writes — organization ───────────────────────────────────────────────── /** Add an organization. */ async addOrg(params: Record): Promise { return this.execute("AddOrg", params); } /** Update an organization. */ async updateOrg(params: Record): Promise { return this.execute("UpdateOrg", params); } /** Delete an organization by sequence number. */ async deleteOrg(orgseq: string): Promise { return this.execute("DeleteOrg", { orgseq }); } /** Insert/update/delete an organization (IUD pattern). */ async iudOrg(params: Record): Promise { return this.execute("IudOrg", params); } /** Add an address. */ async addAddress(params: Record): Promise { return this.execute("AddAddress", params); } /** Update an address. */ async updateAddress(params: Record): Promise { return this.execute("UpdateAddress", params); } /** Delete an address by sequence number. */ async deleteAddress(addseq: string): Promise { return this.execute("DeleteAddress", { addseq }); } /** Insert/update/delete a profile specialty (IUD pattern). */ async iudProfileSpecialty(params: Record): Promise { return this.execute("IudProfileSpecialty", params); } // ─── Writes — on-call ────────────────────────────────────────────────────── /** Add an on-call assignment. */ async addOncallAssignment(params: Record): Promise { return this.execute("AddOncallAssignment", params); } /** Update an on-call assignment. */ async updateOncallAssignment(params: Record): Promise { return this.execute("UpdateOncallAssignment", params); } /** Delete an on-call assignment by sequence number. */ async deleteOncallAssignment(assignmentSeqnum: string): Promise { return this.execute("DeleteOncallAssignment", { assignment_seqnum: assignmentSeqnum }); } /** Add an on-call group. */ async addOncallGroup(params: Record): Promise { return this.execute("AddOncallGroup", params); } /** Update an on-call group. */ async updateOncallGroup(params: Record): Promise { return this.execute("UpdateOncallGroup", params); } /** Delete an on-call group by messaging ID. */ async deleteOncallGroup(oncallMid: string): Promise { return this.execute("DeleteOncallGroup", { oncall_mid: oncallMid }); } /** Delete a member from an on-call group. */ async deleteOncallGroupMember(params: Record): Promise { return this.execute("DeleteOncallGroupMember", params); } /** Add a role to an on-call group. */ async addOncallGroupRole(params: Record): Promise { return this.execute("AddOncallGroupRole", params); } /** Delete a role from an on-call group (composite key: ocmid + ocrole). */ async deleteOncallGroupRole(ocmid: string, ocrole: string): Promise { return this.execute("DeleteOncallGroupRole", { ocmid, ocrole }); } // ─── Writes — work hours ─────────────────────────────────────────────────── /** Add a work hour entry. */ async addWorkHour(params: Record): Promise { return this.execute("AddWorkHour", params); } /** Update a work hour entry. */ async updateWorkHour(params: Record): Promise { return this.execute("UpdateWorkHour", params); } /** * Delete a work hour entry. * @param lid required — the owning listing ID. * @param phrseq required — the work-hour sequence number (returned as phrseq by getWorkHours). */ async deleteWorkHour(lid: string, phrseq: string): Promise { return this.execute("DeleteWorkHour", { lid, phrseq }); } /** * Unassign all work hours from a listing. * @param lid required — the owning listing ID (per amcomapi.xml `UnassignWorkHours` * takes only `lid`, not `mid` — verified live: unassigns all AddWorkHour records for that lid). */ async unassignWorkHours(lid: string): Promise { return this.execute("UnassignWorkHours", { lid }); } // ─── Writes — message groups ─────────────────────────────────────────────── /** Add a static message group. */ async addStaticMessageGroup(params: Record): Promise { return this.execute("AddStaticMessageGroup", params); } /** Update a message group. */ async updateMessageGroup(params: Record): Promise { return this.execute("UpdateMessageGroup", params); } /** * Delete a message group. * @param reqlid required — the requesting listing ID (amcomapi.xml `nullable="false"`; * the pre-existing wrapper was missing this param entirely). * @param grpnum required — the group number to delete. */ async deleteMessageGroup(reqlid: string, grpnum: string): Promise { return this.execute("DeleteMessageGroup", { reqlid, grpnum }); } /** Delete a member from a static message group. */ async deleteStaticMessageGroupMember(params: Record): Promise { return this.execute("DeleteStaticMessageGroupMember", params); } /** Update a member in a static message group. */ async updateStaticMessageGroupMember(params: Record): Promise { return this.execute("UpdateStaticMessageGroupMember", params); } // ─── Writes — paging / messaging ─────────────────────────────────────────── /** Send a message (extended send with additional options beyond SendPage). */ async sendMessage(params: Record): Promise { return this.execute("SendMessage", params); } /** Submit a message for queued delivery. */ async submitMessage(params: Record): Promise { return this.execute("SubmitMessage", params); } /** Send a page to an on-call group. */ async sendGroupPage(params: Record): Promise { return this.execute("SendGroupPage", params); } /** Send a page with an alert flag. */ async sendPageWithAlert(params: Record): Promise { return this.execute("SendPageWithAlert", params); } /** Send a message to a SmartAlert destination. */ async sendToSmartAlert(params: Record): Promise { return this.execute("SendToSmartAlert", params); } // ─── Data Feed ───────────────────────────────────────────────────────────── /** Add a person via the data feed API. */ async dataFeedAddPerson(params: Record): Promise { return this.execute("DataFeedAddPerson", params); } /** Update a person via the data feed API. */ async dataFeedUpdatePerson(params: Record): Promise { return this.execute("DataFeedUpdatePerson", params); } } // Export as both default and named for CJS/ESM compatibility export { SpokService, SpokError }; export default SpokService; // CommonJS compatibility: make `require("spok-api")` return the class directly // with named exports attached (matching cisco-axl pattern) const exportObj = Object.assign(SpokService, { SpokService, SpokError }); module.exports = exportObj;