- API
- Integration with IP telephony
- Getting started [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]
- Manage types
- Global context and isolation
- Manage apps
- Batch actions with app items
- Manage external services
- Scripts in widgets
- Web components
- Access permissions
- Getting started with processes
- Getting started with signatures
- Getting started with file previews
- Getting started with the organizational chart
- Getting started with users and groups
-
Getting started with the
Table data type -
Getting started with the
Category data type - Dynamic event type calculation
- Typical use cases
- API
- API
- Integration with IP telephony
Report a mistake
There is a mistake in the following text:
Feedback sent successfully
Thank you for your input
Integration with IP telephony
Out of the box, the system includes integrations with various IP telephony providers. If the specific integration you need is not available, you can use this API to create your own integration. To do this, you need to create a custom module and implement several functions in the module scripts using TypeScript. Built-in and custom IP telephony integration modules do not differ fundamentally in terms of functionality. The following capabilities will be available to your module:
Limitations
Before implementing the integration module, note the following API limitations:(webhook). If the telephony provider does not allow specifying a URL for message delivery, you must create an intermediary service that transforms the telephony provider's data into a request to the system server. To do this, you can create a [portable service in the module] (https://brix365.com/en/help/platform/portable-microservices.html).
Implementation
To create the integration module, you need to implement the following functions in the custom module scripts:After implementing these functions and saving the script on the module page, you will find a new workspace named// Check the telephony connection. Called when the Check Connection button is clicked on the module page // Returns the connection check status, which will be displayed to the user on the module page async function VoipTestConnection(): Promise<VoipTestConnectionResult> { } // Process a request from the IP telephony provider. Called when a request is made to the module webhook // The `request` parameter contains information about the HTTP request, including HTTP headers and request body contents // The function returns the request processing result, based on which the system will display notifications // about an incoming call, save the call recording, and so on. async function VoipParseWebhookRequest (request: FetchRequest): Promise<VoipWebhookParseResult> { } // Get the list of users from the IP telephony provider side // Called when mapping telephony users to system users after clicking the Configure button on the module page // Returns the list of IP telephony provider users async function VoipGetMembers(): Promise<VoipMember[]> { } // Generate an outgoing call. The function is called when a system user clicks the call button // in the context menu of a Phone field or the Call Back button on the call page. The // `srcPhone` parameter specifies the caller user's number, `dstPhone` specifies the number to call, // and `ext` is the extension. It is recommended to configure the PBX or SIP softphone so that the extension // is automatically dialed using tone dialing after the other party answers the call. async function VoipGenerateCall (srcPhone: string, dstPhone: string, ext?: string): Promise<void> { } // Get the call recording link. The function is called when a system user plays a call recording from the // feed of an App item or when saving the call recording link in the context of the Call App item // in the Telephony Workspace. The `callData` parameter contains the data that was specified when saving // call recording information from the `VoipParseWebhookRequest` function. The function must return a file link async function VoipGetCallLink(callData: any): Promise<string> { } // Called automatically when the webhook URL changes (for example, when the token is updated) // The `webhookUrl` parameter specifies the absolute URL of the integration module webhook. Implementing this function is optional async function VoipOnWebhookUpdated(webhookUrl: string): Promise<void> { }Telephony Settings. This workspace will contain the webhook URL—when data is sent to this URL, the
VoipParseWebhookRequestfunction from the script will be called. In this function, you must process the request and return aVoipWebhookParseResultinstance, based on which the system will display incoming call notifications or save call recording information. You must specify the webhook URL itself in your telephony provider settings. The URL processesGETandPOSTHTTP requests. The URL must also include the requiredtokenparameter.Implementing support for buttons on the call page
When an incoming call is received or an outgoing call is made, the system user sees a [page with information about the current call] (https://brix365.com/en/help/crm/work-with-call.html) in the lower-right corner. Depending on the call state, different buttons may be displayed on this page: Answer Call, End Call, Reassign, and so on. To display these buttons, implement the following functions in the custom telephony module:
// Answer a call. The function is called when a system user clicks the **Answer Call** button on the call page // After that, voice data starts being transmitted between the operator and the customer // The `srcPhone` parameter specifies the caller's phone number, and `dstPhone` specifies the number being called async function VoipAcceptCall(srcPhone: string, dstPhone: string): Promise<void> { } // End a call. The function is called when a system user clicks the **End Call** button on the call page // The call between the operator and the customer is terminated // The `srcPhone` parameter specifies the caller's phone number, and `dstPhone` specifies the number being called async function VoipHangupCall(srcPhone: string, dstPhone: string): Promise<void> { } // Reassign a call. The function is called when a system user clicks the Reassign button on the call page // The current operator's call ends, and the customer is connected to another operator // The `srcPhone` parameter specifies the caller's phone number, `dstPhone` specifies the number being called, // and `redirectTo` is the extension of the operator to whom the call is reassigned async function VoipRedirectCall (srcPhone: string, dstPhone: string, redirectTo: string): Promise<void> { } // Put a call on hold. The function is called when a system user // clicks the **Put on Hold** button on the call page. Voice data transmission between the operator and the customer stops without ending the call // The `srcPhone` parameter specifies the caller's phone number, `dstPhone` specifies the number being called, // and `hold` is the value `true`. It indicates that the call should be put on hold; otherwise, it should be taken off hold async function VoipHoldCall (srcPhone: string, dstPhone: string, hold: boolean): Promise<void> { }If a function is not implemented in the custom telephony module, the corresponding button will not be displayed on the call page.
Implementing CTI panel support for browser-based calls
If the telephony provider supports WebRTC technology, calls can be made directly from the browser using the CTI panel built into the system. It lets you work with calls from a single interface. In this case, installing a SIP softphone is not required.
Interaction between the CTI panel and telephony
Telephony integration in the system CTI panel is implemented through a custom module widget. When an employee selects a telephony provider in the CTI panel, a widget instance is created automatically. Its client scripts call the
connectfunction to initialize the connection to the telephony provider. The widget allows you to:BrowserVoipClient.callmethod is called. As a result, the widget must initiate an outgoing call using the telephony protocol and return an object with call information to the system. For more details about data types, see the example below;BrowserVoipEventSink.callReceivedmethod so that the CTI panel displays information about the incoming call;Configuring a custom widget to work with the CTI panel
To implement a widget for interaction with the CTI panel, follow these steps:browser_voip_client. This code is used by the system to determine which specific widget from the module should be used for integration with the CTI panel;interface BrowserVoipClientCredentials { // Telephony user extension extension: string; // Telephony user login username: string; // Telephony user password password: string; }BrowserVoipClientinterface exceptgetCallIdare required to be implemented:// Established telephony connection // @template TIncomingCall Incoming call // @template TOutgoingCall Outgoing call interface BrowserVoipClient<TIncomingCall = unknown, TOutgoingCall = unknown> { // Disconnect from telephony. Called by the system when the user turns off the CTI panel disconnect(): Promise<void>; // Make an outgoing call. Called by the system when the user enters a number // in the dialer and clicks the Make Outgoing Call button. It can also // be called when making a call through the context menu of the Phone Number field // @ param phoneNumber Phone number to call // @param ext Extension that must be dialed automatically in tone mode // after the connection is established // @returns An object representing a call. In this object, the widget can store // any call data // The object will be passed to other methods of the `BrowserVoipClient` interface when the CTI panel needs // to change the call state call(phoneNumber: string, ext?: string): Promise<TOutgoingCall>; // Answer an incoming call. Called by the system when the user clicks the // answer incoming call button. It appears after a telephony event about // a new incoming call is received. For details, see the description of `BrowserVoipEventSink.callReceived` // @param invite Incoming call that was specified in the argument // of the `BrowserVoipEventSink.callReceived` method accept (invite: TIncomingCall): void; // End a call, that is, hang up. Also called if an incoming call needs to be rejected // @param call Call hangup(call: TIncomingCall | TOutgoingCall): void; // Put a call on hold // @param call Call hold(call: TIncomingCall | TOutgoingCall): void; // Take a call off hold // @param call Call unhold (call: TIncomingCall | TOutgoingCall): void; // Perform a blind transfer to the specified phone number. As a result of calling this method, // the passed call is expected to be ended // @param call Call // @param redirectPhoneNumber Phone number to transfer to blindTransfer (call: TIncomingCall | TOutgoingCall, redirectPhoneNumber: string): void; // Complete an attended transfer. As a result of calling the method, it is expected that // the two specified parties will be connected to each other, and the `transferor` call will transition to // the Call Ended state // @param transferor Current user's call with the customer that needs to be transferred // to employee `caller` // @param caller Current user's call with the employee to whom the call will be transferred attendedTransfer(transferor: TIncomingCall | TOutgoingCall, caller: TIncomingCall | TOutgoingCall): void; // Send a DTMF signal. Called by the system when the user enters a DTMF code in the CTI panel interface // @param call Call // @param key Signal to send. For example: '1', '5', '*', '#' // @returns A Promise that resolves after the signal is sent sendDtmf (call: TIncomingCall | TOutgoingCall, key: string): Promise<void>; // Get the unique call identifier on the telephony side. This identifier must be // the same on the client side in the browser and in the event generated by the // `VoipParseWebhookRequest` function when processing an event through the webhook. The call ID is used by the system to // update call information with additional data from the server. For example, a Call App item from the Telephony Workspace // can be linked to a call in the CTI panel // @ param call Call // @returns The identifier of the call or null if the identifier is unavailable getCallId? (call: TIncomingCall | TOutgoingCall): string | null; }// Object through which the telephony connection `BrowserVoipClient` can send notifications // about call state changes to the CTI panel // @ template TIncomingCall Incoming call // @template TOutgoingCall Outgoing call interface BrowserVoipEventSink<TIncomingCall = unknown, TOutgoingCall = unknown> { // Notify about a new incoming call. The CTI panel will display a prompt to the user // to answer or reject the incoming call // @param invite Object with information about the incoming call. This value will be passed as is to // `BrowserVoipClient.accept` or `BrowserVoipClient.hangup` // @param phoneNumber Phone number from which we are receiving the call callReceived(invite: TIncomingCall, phoneNumber: string) : void; // Notify that the call has ended. In the CTI panel, the call will transition to the Call Ended state // @param call Call callFinished(call: TIncomingCall | TOutgoingCall): void; // Notify that a connection has been successfully established between two parties for the specified call. // It is expected that both parties can hear each other. In the CTI panel, the call will transition to the // In Progress state // @param call Call callEstablished(call: TIncomingCall | TOutgoingCall): void; // Send a telephony connection lost event. This method should be called when // a critical error has occurred due to which it is impossible to automatically restore the connection // to telephony // @param reason Error reason that the user will see disconnected(reason: string): void; }connectfunction in the client scripts. It is called automatically after the system user turns on the CTI panel. If the connection to telephony is successful, this function returns an implementation of theBrowserVoipClientinterface. Later, the system will call the methods of this object depending on user actions in the CTI panel. The method also accepts a parameter of typeBrowserVoipClientCredentials, which contains the extension, login, and password for connecting to telephony. The system administrator fills in this information on the telephony module settings page. TheBrowserVoipEventSinkobject is used to send events to the CTI panel, for example, receiving a new incoming call or changing the call state.async function connect(credentials: BrowserVoipClientCredentials, eventSink: BrowserVoipEventSink): Promise<BrowserVoipClient> { const client: BrowserVoipClient = { // Implement the BrowserVoipClient interface }; try { // Connect to the telephony signaling channel using the data from the `credentials` argument ... // At the moment the method returns, the `BrowserVoipClient` instance must be connected to telephony return client; } catch { // In case of a connection error, close all telephony connections ... // Re-throw the exception so that the user sees // the telephony connection error message in the CTI panel throw; } }Automatic authentication in telephony (SSO)
To allow employees to connect to telephony through the CTI panel, the system administrator must fill in the login and password for each telephony user in the custom module settings. With a large number ofemployees, this can be labor-intensive. To improve security and reduce the workload on the system administrator, it is recommended to automatically retrieve credentials from telephony or a third-party service. The workflow
may look as follows:
voip_supports_single_sign_onwith the Yes/No choice data type. Set the default value for this field to Yes or add it to the module settings form. When this field is set to Yes, the system does not display fields for entering the telephony user's login and password when configuring the CTI panel;api_keywith the String data type. This field stores the API key for telephony authentication.extensionwith the String data type. Used to pass the user's extension for which a token must be obtained;auth_tokenwith the String data type. Used to obtain a token for connecting to telephony.connectmethod in the client scripts. It is used to send arequest to obtain credentials for connecting to telephony. The current user can be obtained by calling the
System.users.getCurrentUser()method. Save the received credentials in the widget context variableauth_token.// Client scripts async function connect(credentials: BrowserVoipClientCredentials, eventSink: BrowserVoipEventSink): Promise<BrowserVoipClient> { // Save the user's extension in a variable so that the server script can access it Context.data.extension = credentials.extension; await Server.rpc.getAuthToken(); // The getAuthToken() call will save the token in the context variable const token = Context.data.auth_token; if (!token) { throw new Error ('Failed to get authentication token'); } // Use `token` to connect to telephony ... } // Server scripts async function getAuthToken(): Promise<void> { const currentUser = await System.users.getCurrentUser(); const extension = Context.data.extension; // API key for the third-party service, usually filled in on the module settings page const apiKey = (await Namespace.getParams() ).data.api_key; const response = await fetch('https://example.com/ auth', { method: 'POST', body: JSON.stringify({ userId: currentUser.id, extension: extension, apiKey: apiKey, }), }); if (response.ok) { const token = await response.text(); Context.data.auth_token = token; } }