Developers

Webhooks

There are certain Benti API events that can trigger an HTTPS POST request to an external service via a webhook. 

In addition, certain events occurring within the Benti instance can also trigger an HTTPS POST request to an external service via a webhook.

This article provides information on both types of webhooks, including how to set them up, which events to subscribe to and what payloads they use.

Benti API webhook

Benti API webhooks are the webhooks that can be triggered by certain Benti API events, which are listed in the section below.

Subscriptions

Before adding a webhook, you must first decide the type of events you want to subscribe to:

Item/event type Description
alert When an alert is added to a ticket
ticket When a (sub)ticket is added or updated
reply When a reply is added to a ticket
user When a user is added or updated
media When a media file is added to a ticket
classification When a classification is added to or removed from the Benti instance
queue When a queue is added or updated in the Benti instance

Setting up a webhook

Once you know the type of events that you want your webhook to receive, you must register the receiving URL:

 POST /v1/webhooks HTTP/1.1
 Content-Type: application/json
 {
    "item": "ticket",
    "url": "https://some.example/endpoint"
    "secret": "SomeRandomString"
 }
 
Caution

The URL must use the 'https' protocol

The response to this call will be the uuid of the webhook that can update or even delete it.

Important

When it performs the above POST call, the system also runs a verification test to make sure that the URL belongs to you. If the test fails, the webhook creation fails too.

The verification consists of an empty GET request to the specified URL, with two relevant headers:

  • "X-Hook-Signature": This header contains the previously specified secret.
  • "X-Inbenta-Challenge": This contains a random string.

In order to complete the verification successfully, the request is expected to return:

  • HTTP code: 200
  • Body: The content of the "X-Inbenta-Challenge" header as plain text
Note

If you want to send multiple webhook item events to the same URL, add a new webhook for each with its own item and the same URL.

Payloads

The payload of the POST request sent to the webhook URL differs depending on the event that has triggered the request.

Each payload contains the following information: 

  • id: The item ID
  • item: The event type that triggered the webhook request (for example “reply”)
  • action: The action that triggered the request (for example “add”)
  • timestamp: A Unix timestamp representing the date and time when the request was sent
  • actor: The user who performed the action that triggered the request
  • parent: The ID of the ticket containing the item for which the request was triggered

For example:

{
   'id': 200, // id of the reply
   'item': 'reply',
   'action': 'add',
   'timestamp': 1660834225,
   'actor': 4014, 
   'parent': 100, 
}
 

The following table presents a summary of which endpoint produces a webhook, depending on the item and subscribed action. If the Endpoint column is empty, this means the corresponding action does not produce a webhook request.

Item Action Endpoint
alert add POST /tickets/{ticketId}/alerts
update
remove
ticket add POST /tickets
POST /tickets/{ticketId}/subtickets
update PUT /tickets/{ticketId}
remove
reply add POST /tickets/{ticketId}/replies
update
remove
user add POST /users
update PUT /users/{userId}
remove
media add POST /media
update
remove
classification add POST /classifications
update
remove DELETE /classifications/{classificationId}
queue add POST /queues
update PUT /queues/{queueId}
remove

Update/Delete webhook subscriptions

You can retrieve a list of all the active webhooks by calling the following endpoint:

 GET /v1/webhooks HTTP/1.1
     Accept: application/json
 {
 }
 

You can update any webhook field at any time using its id:

 PUT /v1/webhooks/{id} HTTP/1.1
 Content-Type: application/json
 {
    "item": "ticket",
    "url": "https://some.example/endpoint"
    "secret": "SomeRandomString"
 }
 

If a webhook is no longer necessary, you can delete it instantly using its id:

 DELETE /v1/webhooks/{id} HTTP/1.1
 Accept: application/json
 {
 }
 

Benti instance webhooks

Benti instance webhooks are webhooks you can configure in the Benti instance itself or by using the Benti API’s POST /webhooks/app endpoint. This type of webhook can be triggered by each of the events listed below.

Subscriptions

Before adding a webhook, you must first decide the type of events you want to subscribe to.

You have the following options

Event Description
answer

The webhook is triggered when an agent answers a ticket in the Benti instance.

create-ticket

The webhook is triggered when a ticket is created in the Benti instance. This does not include tickets created by the Benti API.

create-subticket

The webhook is triggered when a subticket is created in the Benti instance.

close-ticket

The webhook is triggered when a ticket is closed in the Benti instance.

classify-ticket

The webhook is triggered when a ticket is (re)classified in the Benti instance.

change-queue

The webhook is triggered when a ticket in the Benti instance is moved to a different queue.

reply-ticket

The webhook is triggered when an end user replies to a ticket in the Benti instance.

 

Setting up a webhook

Before a webhook can be added to the Benti instance, you need to set up your server to be able to receive Inbenta requests and create the Webhook URL. Make sure you also obtain the secret to the Webhook URL. 

To set up your server to receive Inbenta requests: 

  1. Store the header X-Inbenta-Challenge in the server that will be receiving the webhook requests. This is required so that Inbenta can initiate a handshake to verify that the receiving server is valid and able to receive its HTTPS POST requests.
  2. For security reasons, make sure you have an SSL (Secure Sockets Layer) certificate issued by a certificate authority. This means the SSL certificate cannot be self-signed. The certificate allows sensitive information to be transmitted securely.
  3. Keep in mind that Inbenta only accepts HTTPS requests.

Authentication and requests

Whenever you add a new webhook to your Benti instance, Inbenta sends a GET request to the webhook endpoint (URL) with an automatically generated code in the X-Inbenta-Challenge header. The endpoint should return a 200 (OK) response together with the same header and the received code. This header will only be sent once for each webhook, upon the webhook's creation in your instance. For more information on handshakes, please check out the relevant documentation on the Developers' Portal.

Then, once the webhook has been configured in the Benti instance as instructed in this article, each time the selected events occur, a POST request is sent to the webhook URL with the secret in the X-Hook-Signature HTTPS header for validation, and the payload(s) corresponding to those events. You can find the information that will be sent in each payload in the Payloads section below.

Note that the payload of each request contains the data that was accurate right after the action was completed. Even though the data may have already changed by the time we send the request, it can be used to know the status of the resource right after the action was completed.

Each webhook request will include only the information that was changed through a specific action. If you want to obtain the actual status of a ticket at a certain time in case the information received through the webhook has already changed, send a request to the Benti API.

Payloads

The payload of the POST request sent to the webhook URL differs depending on the event that has triggered the request. Below, you can find which event triggers which payload to be sent.

Each payload contains at least the following information: 

  • id: The request ID the Benti instance generates automatically upon sending the request
  • action: The action that triggered the request (for example “create-ticket”)
  • created_at: The date and time when the request was sent, in the format YYYYMMDDhhmmss
  • project: The name of the instance in which the action was performed

Request sample ANSWER

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{

       "events": [{

           "id": "MDAwMDAwMOSfti9quwKNOg==",

           "action": "answer",

           "created_at": "20170905091635",

           "resource": "PROJECTNAME-00110063",
    
           "type": "ticket",
    
           "user": {

               "name": "name",
        
               "identifier": "email@email.com"

           },
 
           "action_data": {
 
               "text": "text",
 
               "to": [{
 
                   "email": "email@email.com",
 
                   "name": "name"
 
                   }],
 
                   "cc": null,
 
                   "bcc": null
 
           },
 
           "resource_data": {
 
               "creator": {
 
                   "name": "name",
 
                   "identifier": "email@email.com"
 
               },
 
               "queue": {
 
                   "id": 1,
 
                   "name": "queue_name"
 
              },
 
              "source": {
 
                  "id": 1,
 
                  "name": "source_name"
 
              }
 
           },
 
           "project": {
 
               "name": "instance_name"
 
           },
           "attachments": [{
 
               "id": "123",
 
               "url": "image_url",
 
               "name": "Image name.png",
 
               "type": "image\/png",

           }],
    }]
}

The ANSWER payload contains the following information:

  • resource: The resource ID (in this case the ticket ID).
  • type: The event type that triggered the webhook request (in this case “ticket”).  
  • user:
    • name: The name of the agent who answered the ticket.
    • identifier: The email of the agent who answered the ticket.
  • action_data:
    • text: The answer text that was sent.
    • to:
      • email: The email of the user the answer was sent to.
      • name: The name of the user the answer was sent to.
    • cc: The email and name of the user the answer was sent to in CC.
    • bcc: The email and name of the user the answer was sent to in BCC.
  • resource_data:
    • creator:
      • name: The name of the user who created the ticket that was answered.
      • identifier: The email of the user who created the ticket that was answered.
    • queue:
      • id: The Benti ID of the queue the ticket is assigned to.
      • name: The name of the queue the ticket is assigned to.
    • source:
      • id: The Benti ID of the ticket source.
      • name: The name of the ticket source.
  • attachments: Data relevant to the files attached to the ticket reply, if any.
    • id: The ID of the attached file.
    • url: The URL of the attached file.
    • name: The name of the attached file.
    • type: The attached file type.

Request sample CREATE TICKET

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{ 

    "events": [ 

        { 
           "id": "MDAwMDAwMOSfti9quwKNOg==", 

           "action": "create-ticket", 

           "created_at": "20170905091635", 

           "project": "project_name", 

           "body": {

               "ticket_id": "PROJECTNAME-00110063", 

           } 

       } 

   ] 

}

The “body” property of the CREATE TICKET payload contains the following information:

  • ticket_id: The ID of the created ticket

Request sample CREATE SUBTICKET

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{ 

    "events": [ 

        { 
           "id": "MDAwMDAwMOSfti9quwKNOg==", 

           "action": "create-ticket", 

           "created_at": "20170905091635", 

           "project": "project_name", 

           "body": {

               "ticket_id": "PROJECTNAME-00110064",
               "parentId": "PROJECTNAME-00110063", 

           } 

       } 

   ] 

}

The “body” property of the CREATE TICKET payload contains the following information:

  • ticket_id: The ID of the created subticket
  • parentId: The ID of the parent ticket

Request sample CHANGE QUEUE

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{ 
    "events": [ 
        
        { 

            "id": "BViqcuixKxgwAETmUHSsdsS==", 

            "action": "change-queue",
            "created_at": "20170908114619",
            "project": "project_name",
            "body": {
                "ticket_id": "PROJECTNAME-00110063",
                "previous_queue": 1,
                "new_queue": 2,
            }
        }
    ]
}

The “body” property of the CHANGE QUEUE payload contains the following information:

  • ticket_id: The Benti ID of the ticket that was changed to a different queue
  • previous_queue: The Benti ID of the queue the ticket was in before the change
  • new_queue: The Benti ID of the queue to which the ticket was moved

You can find the queue names and IDs in Benti > Settings > Queues.

Request sample CLASSIFY TICKET

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{
    "events": [
        {
            "id": "BViqcuixKxgwAETsECasdG==",
            "action": "classify-ticket",
            "created_at": "20170908115131",
            "project": "project_name",
            "body": {
                "ticket_id": "PROJECTNAME-00110063",
                "previous_classification": "",
                "new_classification": "3,6,10,32",
            }
        }
    ]
}

The “body” property of the CLASSIFY TICKET payload contains the following information:

  • ticket_id: The Benti ID of the ticket whose classification was changed
  • previous_classification: The Benti ID(s) of the classification(s) the ticket had before the change. The IDs of the main and subclassifications are listed sequentially according to the level of each classification. They are separated by commas without spaces.
  • new_classification: The Benti ID(s) of the classification(s) the ticket has now. The IDs of the main and subclassifications are listed sequentially according to the level of each classification. They are separated by commas without spaces.

Request sample REPLY TICKET

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode 

{
    "events": [
        {
            "id": "BViqcuixKxgwAETmVyaseE==",
            "action": "reply-ticket",
            "created_at": "20170908115131",
            "project": "project_name",
            "body": {
                "ticket_id": "PROJECTNAME-00110063",
                "message": {
                    "content": "\tHTML text\n<\/p>",
                    "from": {
                        "id": 15789,
                        "name": "Agent\u00a0Name",
                        "address": "username@example.com",
                        "external_id": null,
                        "is_agent": true,
                    },
                    "attachments": [
                        {
                            "id": "641",
                            "url": "image_url",
                            "name": "Image name.png",
                            "type": "image\/png"
                        }
                    ],
                },
            }
        }
    ]
}

The “body” property of the REPLY TICKET payload contains the following information:

  • ticket_id: The Benti ID of the ticket whose classification was changed
  • message: Data relevant to the message in the ticket reply
    • content: The content of the message in the ticket reply, in HTML format
  • from: The data relevant to the sender of the ticket reply
    • id: The user ID of the sender of the reply
    • name: The user name of the sender of the reply
    • address: The email address of the sender of the reply
    • external_id: The ID originating from the source that is external to Benti, for example the Instagram ID of an Instagram post that was converted to a ticket in Benti
    • is_agent: Whether the sender of the reply is an agent in your Benti instance or not. This value can be either “true” or “false”.
  • attachments: Data relevant to the files attached to the ticket reply, if any
    • id: The ID of the attached file
    • url: The URL of the attached file
    • name: The name of the attached file
    • type: The attached file type

Request sample CLOSE TICKET

# Request to your server

POST /path/to/receive-webhook/

X-Hook-Signature: yourOwnSecretCode

{
    "events": [
        {
            "id": "BViqumc58C4XI+K8N31HQQ==",
            "action": "close-ticket",
            "created_at": "20170908115131",
            "project": "project_name",
            "body": {
                "ticket_id": "PROJECTNAME-00110063",
                "status": 3,
            }
        }
    ]
}

The “body” property of the CLOSE TICKET payload contains the following information:

  • ticket_id: The Benti ID of the ticket that was closed
  • status: The Benti ID of the ticket status, which is 3