Backoffice SDK

Important
Improperly applying customizations with the backoffice SDK can impact the Wix Answers App experience.
The Backoffice SDK enables you to add JavaScript code to customize the Wix Answers App, which is used by agents and administrators. You manage this SDK by adding JavaScript to the Custom JS pane on the Backoffice Custom Code page (https://<tenant_subdomain>.wixanswers.com/app/settings/custom-code).

You can test the code in your browser console before entering it on the Backoffice Custom Code page.

The following are some examples of what you can do using the SDK.
Note
If you have specific integration needs not met using the existing SDK, contact us at support@wixanswers.com with your request.

Methods

addListener(eventType:EventType, listener:function)

Add a listener for an event. Different payload are sent for different events.

Returns: None

The event types are as follows:
Type
Description
Payload
eventTypes.appLoaded
App Loaded
None
eventTypes.ticketLoaded
Ticket page loaded
{ticket: Ticket object, timeline: Ticket timeline object}
eventTypes.ticketUpdated
Ticket updated
{ticket: Ticket object}
eventTypes.ticketSidebarLoaded
Ticket sidebar loaded
{ticket: Ticket object}
eventTypes.ticketWillLoad
Ticket page is about to be loaded
{ticket: Ticket object, timeline: Ticket timeline object}
eventTypes.ticketInfoSectionAdded
An info section was added to a ticket
{sectionTitle: string}
eventTypes.ticketRelationAdded
Article relation added to a ticket
{ticket: Ticket, articleIds: [list of article GUIDs]}
eventTypes.ticketReplied
Agent replied to a ticket (not internal note)
{ticket: Ticket, replyContent: string}
eventTypes.ticketCustomFieldsUpdated
Ticket's custom field value added or modified
{ticket: Ticket, customFields: Map of {<field-name>: <value>}}

value format varies according to field type.
eventTypes.timelineItemLoaded
Timeline item loaded

eventTypes.timelineLoaded
Timeline loaded

eventTypes.ticketEndSession
Agent ended handling the ticket

eventTypes.multipleTicketsReplied
Agent replied in bulk to multiple tickets (not internal notes)
{tickets: [list of ticket objects], replyContent: string}
eventTypes.multipleTicketsRelationAdded
Article relation added in bulk to multiple tickets
{tickets: [list of ticket objects], articleIds: [list of article GUIDs]}
eventTypes.customFieldsPanelConfigurationAdded
Case Details panel loaded



{panelName: string, clearFieldsOnParentChange: Boolean,  customFields: [{id: custom field name, required: Boolean, dependentField: { <value>: [list of other custom field names] },
...},
...]
}
eventTypes.onCallDeviceRendered
Incoming call appears to agent
{ticket: extended ticket object, userPhoneNumber: phone number object}
1
2
3
4
answersBackofficeSdk.addListener(
    answersBackofficeSdk.eventTypes.ticketLoaded,
    function() { console.log("ticket loaded") }
);

addTicketInfoSection(title:string, HTML:string, isOpen:Boolean, tag?:string)

Add custom information section to the right sidebar when viewing a ticket.

Set the third parameter to true to configure that the new section is open by default.
Set the fourth parameter if you are using reorderTicketInfoSections (see below).

Returns: Boolean (true on success, false on failure)

forceSavedRepliesSearchLocale(locale:locale string)

Configure that saved replies are searched only in the specified locale.

Returns: None

getAgentSignature

Get the current agent signature.

Returns: String

getCurrentAgent

Get current agent.

Returns: Agent object

insertHtmlToReplyArea(HTML:string)

Append HTML to the reply area without sending the reply.

Returns: None

notify({content: string})

Pop up a UI notification on the bottom right of the screen.

Returns
: None
1
2
3
answersBackofficeSdk.notify(
  {'content': 'Something wonderful happened!'}
)

relatedArticleAction(articleId:string, action:ArticleAction)

Perform actions regarding related articles. These simulate the actions normally performed by buttons on the page.

Returns: None

The actions are as follows:
Action
Description
on-link
Add link to article as a timeline entry.
on-unlink
Remove timeline link to article.
paste-link
Paste link to article into an agent reply.
use-content
Paste article content into an agent reply.
1
2
3
answersBackofficeSdk.relatedArticleAction('article-GUID', 'use-content');
answersBackofficeSdk.relatedArticleAction('article-GUID', 'paste-link');
answersBackofficeSdk.relatedArticleAction('article-GUID', 'on-link');

reorderTicketInfoSections([section-tag:string, ...])

Order the info sections on the ticket sidebar. Use the following tags, depending on the info section:
  • Default section:
    • recent-tickets
    • technical-data
    • custom-fields
    • case-details
  • Integration:
    • Use the integration title, changing spaces into underscores (_). For example, use Salesforce_-_staging for the integration Salesforce - staging.
  • Custom information section (added using addTicketInfoSection):
    • Use the tag specified when adding the section.

Sections not listed in this method appear at the bottom.
Returns: None
1
2
3
4
5
6
7
8
9
10
11
answersBackofficeSdk.reorderTicketInfoSections([
 "Salesforce",
 "recent-tickets",
 "technical-data",
 "custom-fields",
 "case-details",
 "Shopify",
 "Jira",
 "Hubspot",
 "Shopify"
]);

setAgentSignatureOverride(ticketProperties:structure, currentSignature:string)

Set a dynamic signature for the current agent. The signature changes based on the ticket. The parameters sent to this function include properties of the ticket object and the current, existing signature. The properties structure is as object, as follows:

{
// Ticket custom fields, map of field names to values
    customFields: {"field GUID": "value1", "field GUID": "value2", ...},
// User custom fields, same as above
    usersCustomFields: {...},
// Language code, such as "en"
    locale: string,
// List of label objects
    labels: [Label object 1, Label object 2, ...]
}

Note that some custom fields may not appear in the UI. If you want the signature to change when a user selects a custom field, ensure that this custom field is one that appears in the UI.

This function returns the new signature.

Returns: The new signature (string)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
answersBackofficeSdk.setAgentSignatureOverride((ticketProperties, signature) => {

  if (ticketProperties.customFields && ticketProperties.customFields.regulator) {
     return`${signature} <br /> ${ticketProperties.customFields.regulator}`;
  };

  if (ticketProperties.labels && ticketProperties.labels.some(label=>label.name === 'Twitter ticket')) {
     return`${signature} <br /> Sent from twitter`;
  };

  const ageCustomFieldId = '8cfb43d5-2890-4902-8133-db8837ee17c7';
  if (ticketProperties.usersCustomFields && ticketProperties.usersCustomFields[ageCustomFieldId] === 30) {
     return`${signature} <br /> is 30 years old`;
  }

  if (ticketProperties.locale && ticketProperties.locale === 'fr') {
      return `${signature}, <br /> France`;
  }    
  return signature
});

setCustomFieldsPanelConfiguration({panelName:string, clearFieldsOnParentChange:Boolean, fields:[see below]})

Display an additional custom fields panel (known as the Case Details panel) alongside tickets in the app, and configure which custom fields appear in this panel. In addition, configure field dependencies for this panel. The dependencies enable you to define which custom fields appear in the panel depending on the values selected in other custom fields in this panel.

If you do not call this method, the panel does not appear.

The input contains a list of field structures, each one defining a field and optionally its dependencies. To have a field appear in all cases, not as a dependency, it must be at the top level in one of these structures. To have it appear as a dependency, it must be within a dependentFields sublevel.

Dependencies can be cascaded; in other words, you can configure field-B to appear only if a certain value is selected for field-A and for field-C to appear only if a certain value is selected for field-B.
Case Details Panel Only
This method does not affect the custom fields that appear in the Custom Fields panel, which always displays all custom fields.
Note
Each custom field MUST NOT appear more than once. In other words, each field must a) not appear, b) be a top level field, or c) be a dependent field of exactly one other field.
The input is as follows. Setting required for a field in the input overrides the mandatory setting defined for that field.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
answersBackofficeSdk.setCustomFieldsPanelConfiguration({
  panelName: 'Panel Name (this field is mandatory)',
  clearFieldsOnParentChange: Boolean,
  fields: [
    {
      id: '<custom field 1 GUID>',
      required: Boolean, 
      dependentFields: {
        <custom field 1 value>: [
          {
            id: '<custom field 2 GUID>',
            required: Boolean,
            dependentFields: { ... }
          },
          ...
        ],
        ...
      },
      ...
    },
 ...
  ]
});
For example, if custom field 1 value is 5, then custom field 2 appears on the page only if 5 if selected for the value in custom field 1 value. If the value is changed to something other than 5, the dependent fields are rehidden. Values in hidden fields are not submitted with the contact form.

If the value is changed, the dependent fields are rehidden in the panel (but continue to appear in the Custom Fields panel, as usual).

If you run this before the page is loaded, it will take effect when the page is loaded.

clearFieldsOnParentChange: When set to false (default), when you change a parent field value, values in all (now-hidden) dependent fields remain as they are. When set to true, all values are cleared from these dependent fields.
Returns: None

In the following example, the custom field OS Type appears in the panel. When the user selects Windows as a value for this field, the field Windows Version appears. When the user selects XP as a value for the Windows Version field, the field Patch Level appears. None of the fields are mandatory fields.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
answers.setCustomFieldsPanelConfiguration( {
  fields: [
  {
    id: '77bc8694-5ccf-436c-ab2b-543563a5f425',
    required: false,
    dependentFields: {
      Windows: [
        {
          id: 'bd948e62-a3fd-4cf0-87f3-ee6a0ae7f3fa',
          required: false,
          dependentFields: {
            XP: [
              {
                id: 'd367738e-368e-41fe-9289-1a5cbbc3c239',
                required: false,
              }
            ]
          }
        }
      ]
    }
  }
  ]
});

setEndSessionCheck(handler:function(ticket:Extended Ticket Object, )

Check whether the agent can end handling a ticket. The parameter is a callback function that can be used, for example, to display a confirmation pane. The ticket object is sent to the callback function.

Returns: Boolean: true to end handling the ticket, false otherwise.
1
2
3
4
5
6
answers.setEndSessionCheck((ticket) => {
  if (ticket[...] > ...) {
    return false;
  }
  return true;
});

setInactiveAssignEntetiesCallback(ticket:Extended Ticket Object)

Set inactive agents and/or groups in the ticket assign component (on the left in the ticket page footer). This function is asynchronous. The parameter to the function includes the ticket. The function returns a map of agent/group GUIDs and reasons why they are inactive (the reason appears in the mouseover).

Returns: Structure (see above)
1
2
3
4
5
6
7
answersBackofficeSdk.setInactiveAssignEntetiesCallback(async (ticket) => {
    return {
        'group-GUID': 'Outside working hours',
        'group-2-GUID': 'Does not support ticket language',
        'agent-GUID': 'Agent is busy',
    }
});

setNewTicketSettingsOverride(settings:structure)

Configure the pane that appears when the user selects New Ticket.

The input is an object, as follows:

{
    tab: 'by-agent' | 'on-behalf', // Whether to open the To a Customer or On Behalf of a
                                                // Customer tab, by default. The default is by-agent
                                                // (To a Customer).
    additionalInfoOpen: boolean,  // Whether to expand the Additional Ticket info section when
                                                      // the pane opens. The default is false.
    customerInfoOpen: boolean,  // Whether to expand the Customer info section when
                                                     // the pane opens. The default is false.
    additionalActionsOpen: boolean,  // Whether to expand the Additional Actions section when
                                                            // the pane opens. The default is false.
};

Returns: None
1
2
3
4
5
6
answersBackofficeSdk.setNewTicketSettingsOverride({
      tab: 'on-behalf',
      additionalInfoOpen: true,
      customerInfoOpen: true,
      additionalActionsOpen: false
});

setTicketPageCustomFieldsFilter(filters:object)

Filter custom fields available to select in the custom fields picker.

The input is an object, as follows:

{
    return {
       customerFields: [<list of user custom fields to include>],
       companyFields: [<list of company custom fields to include>],
       ticketFields: [<list of ticket custom fields to include >]
    }
}

Note that for ticket custom fields (only), use the ticket field GUID. For user and company custom fields, use the custom field names.

If a parameter is not included, then all fields of that type appear in the custom fields picker. If the parameter is included but it is empty, then no fields of that type appear in the custom fields picker.

Returns: None
1
2
3
4
5
6
7
answersBackofficeSdk.setTicketPageCustomFieldsFilter(() => {
    return {
      customerFields: ['fn1'],
      companyFields: ['fn2'],
      ticketFields: ['d367738e-368e-41fe-9289-1a5cbbc3c239']
    };
});

setTicketRelatedArticlesFilter(filters:object)

Filter articles available to select in the related articles picker.

The input is an object, as follows:

{
    categoryIds: [<list of categories to include if the article matches any of them>],
    excludeCategoryIds: [<list of categories to exclude if the article matches any of them>],
    hasAllOfLabelIds: [<list of labels to include if the article matches all of them>],
    hasAnyOfLabelIds:  [<list of labels to include if the article matches any of them>],
    notHasAnyOfLabelIds: [<list of labels to exclude if the article matches any of them>],
}

Returns: None

Examples

Adding a Custom Section in the User Information Sidebar

To create a custom section in the user's information side bar inside a ticket page, add two methods: 
  • answersBackofficeSdk.addListener
  • answersBackofficeSdk.addTicketInfoSection

The first method enables Wix Answers to listen to the "ticket page loaded" event and receive the ticket's data. The second enables Wix Answers to add custom sections to the side bar.
Here is an example of a snippet that queries some service, checks if the user that opened the ticket is a "premium" user or not, and adds a custom section to the ticket page side bar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function isPremiumUserByEmail(email, cb) {
 var isPremium = Math.random() > 0.5; //dummy check, replace this with an AJAX call to an external service, or any other meaningful action
 cb(isPremium);
}

function addPremiumUserSidebarItem(isPremium) {
    answersBackofficeSdk.addTicketInfoSection('Custom Data', '<p>Premium: ' + isPremium + '</p>');
}

answersBackofficeSdk.addListener(answersBackofficeSdk.eventTypes.ticketLoaded, function (ticketData) {
    console.info(ticketData);
    isPremiumUserByEmail(ticketData.user.email, function (isPremium) {
    
        addPremiumUserSidebarItem(isPremium);
    });
});
Test this script by adding it in the developers console and then navigating to a ticket page. To add this to your site, enter the script in the Custom JS pane on the Backoffice Custom Code page.

When the script is active, your sidebar includes the following:

Hide Widgets from the Settings Menu

Add the function answersBackofficeSdk.setHiddenWidgetIds to make widgets accessible only using a direct link. This is useful if you want to prevent accidental changes to your widget's settings.
1
2
3
4
answersBackofficeSdk.setHiddenWidgetIds([
    'a601657c-d618-be0f-a943-e6181512073f',
    'b342347a-1528-4fed-2323-234234ababa2'
]);