> For the complete documentation index, see [llms.txt](https://docs.sharelogic.com/unifi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sharelogic.com/unifi/integration-guides/freshservice/freshservice-customer-service-case-template-webhook.md).

# Freshservice Customer Service Case Template(Webhook)

## Overview

The Freshservice template acts as a starting point for building an integration between Unifi and Freshservice. This version of the template integrates ServiceNow Customer Service Case (`sn_customerservice_case`) with tickets on Freshservice. This integration works by sending data bi-directionally, using messages from Unifi and Webhooks in Freshservice.

{% hint style="warning" %}
This document and accompanying template are provided for general use only. Information may be incomplete, outdated, or inaccurate. No responsibility or liability is accepted for any use or reliance on its contents. Users should review and verify all information independently.
{% endhint %}

<table data-header-hidden data-search="false"><thead><tr><th>Item</th><th>Value</th></tr></thead><tbody><tr><td>Source System</td><td>ServiceNow</td></tr><tr><td>Target System</td><td>Freshservice</td></tr><tr><td>Direction</td><td>Bidirectional</td></tr><tr><td>Source Record</td><td><code>sc_customerservice_case</code></td></tr><tr><td>Target Record</td><td><code>Ticket</code></td></tr><tr><td>Inbound sync method</td><td>Webhooks</td></tr><tr><td>Target API</td><td>Freshservice API v2</td></tr><tr><td>Template Version</td><td>1.0.0</td></tr></tbody></table>

To understand the template's construction, it helps to have a baseline understanding of the Freshservice API:

### Freshservice API <a href="#freshservice-api" id="freshservice-api"></a>

Freshworks has a range of API's to interact with their services; this template focuses on tickets and notes as those combine to closely resemble the ServiceNow Task structure with journal fields being used as a stand-in for notes.

* Updating [tickets](https://developers.freshservice.com/api/#tickets) `PUT /api/v2/tickets/[ticket_id]` allows for updating of state, assigned agent and other details.
* Creating [notes](https://developers.freshservice.com/api/#conversations) on Freshservice requires a call to `POST /api/v2/tickets/[ticket_id]/notes`, so some state transitions where a single action is taken of ServiceNow lead to two events being sent to Freshservice, updating the ticket and creation of a note.

### Features <a href="#features" id="features"></a>

* Bidirectional creation, updating and closing of tickets.
* Attachment sending outbound.

#### **Issues**

For full details see: [Limitations](#limitations)

* Automation in Fresh doesn't include an event for all updates, so some changes may not be captured.
* Freshservice automation doesn't allow filtering out updates made by the integration user. These are mitigated in the template, though they may cause unexpected changes.

### **Pre-requisites**&#x20;

* Access to a Freshservice instance.
  * Including a user with the API-key option enabled
  * Access to automation on that instance.
* (Optional) A custom field on Freshservice to store the ServiceNow incident number.
* A ServiceNow development instance with Unifi installed.

## Implementation <a href="#implementation" id="implementation"></a>

The following describes the templates configuration on ServiceNow and the steps to implement on Freshservice. Please review how this configuration should be translated to your own instance.

### Usage <a href="#usage" id="usage"></a>

1. Configure the integration in both systems.
2. Create a ticket/Incident that triggers the integration.
3. Make an update on the other system.
4. If this works set about customising the template for your use-case.

### ServiceNow configuration

To configure open the integration's connection section and create a new connection, set direction to Bidirectional and 'Endpoint URL' to the URL of the target Freshservice instance, this will likely look like `https://CHANGEME.Freshservice.com`\
Next click on the connection and select outbound, here's where we configure outbound authentication, for testing we'll use basic. Select the authentication dropdown and select basic. A User and Password box will appear. For these enter your [Freshservice API key](https://crmsupport.freshworks.com/support/solutions/articles/215517-how-to-find-your-api-key) into the User section and enter 'X' into the password.

Setup an inbound user on ServiceNow for the integration to log-in through, this user will need the `x_snd_eb_integration` and `sn_customerservice_manager` roles. Select this user on the inbound section of the connection.

#### **New fields**

The following fields were added to ServiceNow for use in this integration. The only field currently in use is `u_correlation_id` on the `sys_user` table. The others will likely be needed if user groups are to be synced and if state mappings are changed from direct to an more complex mapping system.

| Field                                      | Table                     | Type         | Reason                                                                                          |
| ------------------------------------------ | ------------------------- | ------------ | ----------------------------------------------------------------------------------------------- |
| u\_correlation\_id                         | sys\_user                 | String (100) | Connecting Freshservice and ServiceNow users.                                                   |
| <p>u\_correlation\_id<br>{Not used}</p>    | sys\_user\_group          | String (100) | Connecting Freshservice and ServiceNow groups.                                                  |
| <p>u\_correlation\_state<br>{Not used}</p> | sn\_customerservice\_case | String (32)  | States such as Wait 3rd party on Freshservice should open out ticket without re-opening theirs. |

#### **Choice Mapping**

Mappings between fields will need to be reviewed to see if they match your configuration. These used the `Choice_int_FD` field map as Freshservice expects values to be sent as integers (1,2,3) rather than strings containing integers ("1","2","3"). This field map looks for a mapping on the parent field map regardless of if inheritance is enabled.

| Field SN      | Field FD | Configuration                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| contact\_type | source   | <p>Field stores how the customer created the ticket, values on ServiceNow are different to Freshservice, so the mapping is a best guess and may vary by configuration.<br>This field is required for create messages on Freshservice so defaults to 2(Portal) as this is the Freshservice default.</p>                                                                                                                                                                           |
| state         | status   | The state field maps between the system states, Freshservice has 3 awaiting state (Pending, Waiting on Customer, Waiting on Third Party), these are all mapped inbound to Awaiting info. Depending on the relationship between the integrated systems, one may be the 'Third Party' for the other so these states may need to be mapped differently. Defaults for this field also contains an override function that maps 'Open' to 'New' if no agent is assigned on ServiceNow. |
| priority      | priority | <p>Maps priority between Freshservice and ServiceNow.<br>- ServiceNow OOTB 1 is Critical, while on Freshservice it's 4.<br>- Freshservice sends the string value of priority (Low, Medium, High, Critical), but expects the integer values</p>                                                                                                                                                                                                                                   |

### Freshservice configuration

Freshservice may be configured to send data to ServiceNow using [Automations](https://crmsupport.freshworks.com/support/solutions/articles/132589-using-webhooks-in-automation-rules).\
If using webhooks a custom header `X-SND-EB-Message-Name` may be used to select which Unifi message is triggered, otherwise the Unifi Integration message identification script will be used. For details on the message bodies sent when configuring this template see the Message bodies section.

#### Configuration Variables

The following variables are used in the integration to set defaults and properties. They will need to be configured for the integration

| Key                        | Value                                                 | Usage                                                                                                                                                                                                           |
| -------------------------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| account                    | *customer\_account\_sys\_id1234*                      | Default account for inbound cases to be created on.                                                                                                                                                             |
| default\_assignment\_group | *sys\_user\_group\_sys\_id1234*                       | Default assignment group to assign new cases created via the integration to.                                                                                                                                    |
| default\_contact           | {Freshservice:Unique\_external\_id}                   | Default contact sent to Freshservice if no contact is set on a case created in ServiceNow. This is sent in the field Unique\_external\_id. If in use a user should be set-up in Freshservice with a matching ID |
| default\_user              | {Freshservice:id}                                     | ID of the default user to update Freshservice tickets as.                                                                                                                                                       |
| send\_matched\_user        | true/false                                            | If true and the user making the update on ServiceNow has a u\_correlation\_id, the users id will be sent. See Feedback loop for why this may be set a false.                                                    |
| source\_tag                | `<span style="display:none">SOURCE:ServiceNow</span>` | Hidden text that can be filtered for in outbound notes senders to prevent it sending notes sent inbound by ServiceNow. See Feedback loop                                                                        |

### **Message bodies**

The following message bodies were used in automations on Freshservice to send data to ServiceNow. This is just a guide and should be reviewed based on your data protection policies and requirements.

**Create, Update & state changes**

Message used:

* Create
* Update
* Pending
* WaitingOnCustomer
* WaitingThirdParty
* Resume
* Resolve
* ReOpen
* Close

```json
{
	"email": "{{ticket.contact.email}}",
	"name": "{{ticket.contact.name}}",
	"phone": "{{ticket.contact.phone}}",
	"priority": "{{ticket.priority}}",
	"source": "{{ticket.source}}",
	"status": "{{ticket.status}}",
	"due_by": "{{ticket.due_by_time}}",
	"subject": "{{ticket.subject}}",
	"description": "{{ticket.description}}",
	"id": "{{ticket.id}}"
}
```

**Comment**

```json
{
	"body": "{{ticket.latest_public_comment}}",
	"id": "{{ticket.id}}"
}
```

**Worknote**

```json
{
	"body": "{{ticket.latest_private_comment}}",
	"id": "{{ticket.id}}"
}
```

Log group or assignee changes:

```json
{
	"body": "Freshservice group or agent changed\nGroup: {{ticket.group.name}}\nAgent: {{ticket.agent.name}}",
	"id": "{{ticket.id}}",
}
```

## Limitations

### Feedback loops <a href="#feedback-loop" id="feedback-loop"></a>

Automations in Freshservice offer limited options to filter when to trigger. As a result updates sent by ServiceNow often cause an automation on Freshservice to Trigger. This then repeats the action on ServiceNow which recognises the event was done over the integration and prevents it causing looping. For updates to the Incident/Ticket this doesn't create issues, for Notes and comments it can lead to them being created twice.

This is avoided by adding a `source_tag` onto the end of Comments and Work\_notes sent to Freshservice which adds a hidden text to this field. When the automations on Freshservice see the text in this tag they stop processing, preventing double note creation. A caveat of reflected updates is that the data sent outbound needs to be the same as the data that will be sent in the response so as not to overwrite data.

#### **Other solutions attempted**

To prevent feedback, we looked into the following options, but at time of writing, all of them missed a required feature.

* Sending updates in with only one user and not sending updates made by that user in automations.
  * Automations can be triggered by only select users, but there isn't an option for all users except the selected.
* Filtering tickets on the ServiceNow side by the updating user.
  * This information is not available in Fresh automations to send outbound.

### Sending attachments from Freshservice <a href="#sending-attachments-from-freshservice" id="sending-attachments-from-freshservice"></a>

The integration may add attachments to the Freshservice ticket from ServiceNow but isn't configured the other way round. This is because attachments in Freshservice are sent as links to the attachment and don't send the attachment itself. The description field on ServiceNow is set to remove these links as they can't be set to clickable. While in journal fields these links are picked up and reformatted to be clickable in ServiceNow.

In the Polling case template these attachments may be captured using put requests. Additional guidance is given in 'Configuring Inbound attachments'.

### **Missing features**

The following features may be desirable depending on your configuration and may be added in future template versions. Only missing features where a ServiceNow feature matches a Freshservice one are noted. Some of these features will not be implemented as they would make the template harder to customise for general use.

* Attachments added to ticket are not sent to ServiceNow.
* Rejection of reflected messages on ServiceNow.
* Sending attachments in journal fields on ServiceNow.
* Cancelled state on ServiceNow could be mapped to deleted.
* Assignment\_group matching: Lookup inbound assignment groups and send a group outbound if it has a correlation id that may be matched with Freshservice.

## Messages

### Outbound

All outbound messages are postfixed with \[Out] and are sent from ServiceNow to Freshservice.\
Messages Prefixed with 'Note' send a note with information about an update like a state change or details added.\
See the image below for an overview of when the different messages are sent based on the state in ServiceNow.

| Message           | Endpoint | Trigger(ServiceNow)                                       | Functionality                                                                                 | Freshservice state |
| ----------------- | -------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------ |
| Create            | Ticket   | An unbonded ticket is added to the linked account         | Create the Ticket in Freshservice.                                                            | Open               |
| Update            | Ticket   | Case updates that doesn't change state.                   | Send the update to Freshservice                                                               | -                  |
| Accept            | Ticket   | Case moves from New to Open                               | No special functionality. Updates basic ticket fields.                                        | Open               |
| NoteAssignee      | Notes    | Assignee or group changes or case moves from New to Open. | Inform Freshservice agents about assignment status on ServiceNow.                             | -                  |
| AwaitInfo         | Ticket   | Case moves from Open to Awaiting Info                     | No special functionality. Updates basic ticket fields.                                        | -                  |
| ReceivedInfo      | Ticket   | Case moved from Awaiting Info to Open                     | No special functionality. Updates basic ticket fields.                                        | -                  |
| Resolve           | Ticket   | Case moves to Resolved                                    | No special functionality. Updates basic ticket fields.                                        | Resolved           |
| NoteResolution    | Notes    | Case moves to Resolved                                    | Create a private note with ServiceNow's resolution information.                               | Resolved           |
| ReOpen            | Ticket   | Case moves from Resolved to Open                          | No special functionality. Updates basic ticket fields.                                        | Open               |
| NoteCancellation  | Notes    | Case state changes to Cancelled                           | Add a note to Freshservice that the case has been cancelled on ServiceNow and break the bond. | -                  |
| Close             | Ticket   | Case moves to Closed                                      | No special functionality. Updates basic ticket fields.                                        | Closed             |
| CreatePrivateNote | Notes    | Worknote added                                            | Create the worknote as a private note on Freshservice.                                        | -                  |
| CreatePublicNote  | Notes    | Comment added                                             | Create the comment as a public note on Freshservice.                                          | -                  |
| AddAttachment     | Ticket   | Attachment is added to the Case.                          | Add attachments to the ticket.                                                                | -                  |

Transitions between case states in ServiceNow are shown below:

<figure><img src="https://3662067745-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDk6VgKBXe6rYT8F9wuaY%2Fuploads%2FPs2gibrBpwBi7SfcR9z0%2FCase-transitions-FD.png?alt=media&amp;token=cb77a90d-ac22-4262-8d86-643d322d3cd6" alt=""><figcaption></figcaption></figure>

### Inbound

All outbound messages are postfixed with \[In] and are sent into ServiceNow from Freshservice.\
See the image below for an overview of when the different messages are sent based on the status in Freshservice.

| Message             | Trigger(Freshservice)                                                           | Functionality                                          | ServiceNow State                                          |
| ------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------- |
| Create              | Ticket meets condition for bonding with ServiceNow.                             | Create the Case in ServiceNow.                         | New/ Open depending on if the agent exists on ServiceNow. |
| Update              | Update is made to the ticket that doesn't change state.                         | Update the Case.                                       | -                                                         |
| Comment             | Public Note is added to a bonded ticket.                                        | Add a comment to the Case.                             | -                                                         |
| Worknote            | Private Note is added to a bonded ticket.                                       | Add a work\_note to the Case.                          | -                                                         |
| Pending             | State changes to Pending.                                                       | Change state and sync basic ticket fields.             | Awaiting Info                                             |
| WaitingThirdParty   | State changes to Awaiting Third Party.                                          | Change state and sync basic ticket fields.             | Awaiting Info                                             |
| Waiting on Customer | State changes to Waiting on Customer.                                           | Change state and sync basic ticket fields.             | Awaiting Info                                             |
| Resume              | Case is resumed from an on-hold state. (Awaiting Customer/Third Party/ Pending) | Change state and sync basic ticket fields.             | Open                                                      |
| Resolve             | State is changed to Resolved.                                                   | Change state and sync basic ticket fields.             | Resolved                                                  |
| ReOpen              | State changes from Resolved to Open.                                            | Change state and sync basic ticket fields.             | Open                                                      |
| Close               | State is changed to Closed.                                                     | Change state, sync basic ticket fields and close bond. | Closed                                                    |

Transitions between states in Freshservice are shown below:

![](https://docs.sharelogic.com/unifi/~gitbook/image?url=https%3A%2F%2F3662067745-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FDk6VgKBXe6rYT8F9wuaY%252Fuploads%252FLqlJJ7XqEifV2mEWu3ED%252FFreshservice-Ticket-Transitions.png%3Falt%3Dmedia%26token%3D6ef2ed94-5982-46ba-b09c-83fb81628665\&width=768\&dpr=3\&quality=100\&sign=1c7c998b\&sv=2)

## Conclusion <a href="#conclusion" id="conclusion"></a>

With the above guidance, you should be able to configure a Freshservice Webhook integration in Unifi. If you encounter any difficulties, please reach out to support, and we would be happy to help.

***

## Change History

| Version | Date       | Changes          |
| ------- | ---------- | ---------------- |
| 1.0.0   | 2026-07-29 | Initial template |
