Available Events

Event Name Event Code (X-Desk-Event) Payload
Ticket Created ticket.created Ticket
Ticket Deleted ticket.deleted ID Only
Ticket Note ticket.note Thread
Agent Reply ticket.agent.reply Thread
Customer Reply ticket.customer.reply Thread
Ticket Assigned ticket.assigned Ticket Assigned
Ticket Unassigned ticket.unassigned Ticket Assigned
Ticket Priority ticket.priority Ticket Priority
Ticket Merged ticket.merged Ticket Merged
Ticket Moved ticket.moved Ticket Moved
Thread Edited thread.edited Thread
Thread Deleted thread.deleted ID Only
Customer Created customer.created Customer
Customer Edited customer.edited Customer
Customer Deleted customer.deleted ID Only
Agent Created agent.created Agent
Agent Edited agent.edited Agent
Agent Deleted agent.deleted ID Only
Inbox Created inbox.created Inbox
Inbox Edited inbox.edited Inbox
Inbox Deleted inbox.deleted ID Only

Payloads

Below are example payloads sent, see the Available Events table for which payload is sent for which events.

When given eventCreatorId is the id of the agent that caused this event.

ID Only

The id property is dependent on the event, e.g for ticket.deleted it is the tickets id and customer.deleted the customers.

{
    "id": 1
}

Ticket

{
  "ticket": {
    "updatedAt": "2016-06-06T09:14:36.426741207+01:00",
    "createdAt": "2016-06-06T09:14:36.426741207+01:00",
    "state": "active",
    "threads": [
      {
        "updatedAt": "2016-06-06T09:14:36.429692802+01:00",
        "createdAt": "2016-06-06T09:14:36.429692802+01:00",
        "threadType": {
          "name": "message",
          "id": 1
        },
        "customer": {
          "linkedinURL": "",
          "googlePlusURL": "",
          "twitterURL": "",
          "facebookURL": "",
          "address": "",
          "mobile": "",
          "phone": "",
          "jobTitle": "",
          "company": "",
          "avatarURL": "https:\/\/digitalcrew.teamwork.com\/desk\/images\/avatars\/animals\/cat.png",
          "email": "joe@bloggs.com",
          "lastName": "Bloggs",
          "firstName": "Joe",
          "id": 1
        },
        "body": "I tried to do this and it didn't work...",
        "ticketId": 1,
        "id": 1
      },
      {
        "updatedAt": "2016-06-06T09:14:36.430863412+01:00",
        "createdAt": "2016-06-06T09:14:36.430863412+01:00",
        "threadType": {
          "name": "message",
          "id": 1
        },
        "agent": {
          "avatarURL": "https:\/\/digitalcrew.teamwork.com\/desk\/images\/avatars\/animals\/sheep.png",
          "lastName": "Agent",
          "firstName": "Jane",
          "id": 1
        },
        "body": "Have you tried doing...",
        "ticketId": 1,
        "id": 2
      },
      {
        "updatedAt": "2016-06-06T09:14:36.433186639+01:00",
        "createdAt": "2016-06-06T09:14:36.433186639+01:00",
        "threadType": {
          "name": "note",
          "id": 3
        },
        "agent": {
          "avatarURL": "https:\/\/digitalcrew.teamwork.com\/desk\/images\/avatars\/animals\/sheep.png",
          "lastName": "Agent",
          "firstName": "Jane",
          "id": 1
        },
        "body": "This is a private note",
        "ticketId": 1,
        "id": 3
      }
    ],
    "type": {
      "name": "Problem",
      "id": 1
    },
    "priority": {
      "sortOrder": 0,
      "color": "",
      "name": "Low",
      "id": 1
    },
    "status": {
      "color": "#44d335",
      "code": "active",
      "name": "Active",
      "id": 1
    },
    "tags": [
      {
        "color": "",
        "name": "needs-help",
        "id": 1
      },
      {
        "color": "",
        "name": "hard-fix",
        "id": 2
      }
    ],
    "files": null,
    "agent": {
      "avatarURL": "https:\/\/digitalcrew.teamwork.com\/desk\/images\/avatars\/animals\/sheep.png",
      "lastName": "Agent",
      "firstName": "Jane",
      "id": 1
    },
    "customer": {
      "linkedinURL": "",
      "googlePlusURL": "",
      "twitterURL": "",
      "facebookURL": "",
      "address": "",
      "mobile": "",
      "phone": "",
      "jobTitle": "",
      "company": "",
      "avatarURL": "https:\/\/digitalcrew.teamwork.com\/desk\/images\/avatars\/animals\/cat.png",
      "email": "joe@bloggs.com",
      "lastName": "Bloggs",
      "firstName": "Joe",
      "id": 1
    },
    "subject": "Help!",
    "id": 1
  },
  "inbox": {
    "state": "active",
    "name": "Support",
    "id": 1
  }
}

Ticket Assigned

On ticket.unassigned the agent property will not be given.

{
    "agent": {
        "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/sheep.png",
        "firstName": "Jane",
        "id": 1,
        "lastName": "Agent"
    },
    "eventCreatorId": 1,
    "id": 1
}

Ticket Priority

{
    "eventCreatorId": 1,
    "id": 1,
    "priority": {
        "color": "",
        "id": 1,
        "name": "Low",
        "sortOrder": 0
    }
}

Ticket Merged

{
    "eventCreatorId": 1,
    "id": 1,
    "mergedToTicketId": 200
}

Ticket Moved

{
    "eventCreatorId": 1,
    "id": 1,
    "newInboxId": 2,
    "oldInboxId": 1
}

Thread

Example agent message thread:

{
    "thread": {
        "agent": {
            "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/sheep.png",
            "firstName": "Jane",
            "id": 1,
            "lastName": "Agent"
        },
        "body": "Have you tried doing...",
        "createdAt": "2016-04-28T09:35:11.197304718+01:00",
        "id": 2,
        "threadType": {
            "id": 1,
            "name": "message"
        },
        "ticketId": 1,
        "updatedAt": "2016-04-28T09:35:11.197304718+01:00"
    }
}

Example customer message thread:

{
    "thread": {
        "body": "I tried to do this and it didn't work...",
        "createdAt": "2016-04-28T09:35:11.196119068+01:00",
        "customer": {
            "address": "",
            "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/cat.png",
            "company": "",
            "email": "joe@bloggs.com",
            "facebookURL": "",
            "firstName": "Joe",
            "googlePlusURL": "",
            "id": 1,
            "jobTitle": "",
            "lastName": "Bloggs",
            "linkedinURL": "",
            "mobile": "",
            "phone": "",
            "twitterURL": ""
        },
        "id": 1,
        "threadType": {
            "id": 1,
            "name": "message"
        },
        "ticketId": 1,
        "updatedAt": "2016-04-28T09:35:11.196119068+01:00"
    }
}

Example note thread:

{
    "thread": {
        "agent": {
            "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/sheep.png",
            "firstName": "Jane",
            "id": 1,
            "lastName": "Agent"
        },
        "body": "This is a private note",
        "createdAt": "2016-04-28T09:56:12.568495585+01:00",
        "id": 3,
        "threadType": {
            "id": 3,
            "name": "note"
        },
        "ticketId": 1,
        "updatedAt": "2016-04-28T09:56:12.568495585+01:00"
    }
}

Customer

{
    "customer": {
        "address": "",
        "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/cat.png",
        "company": "",
        "email": "joe@bloggs.com",
        "facebookURL": "",
        "firstName": "Joe",
        "googlePlusURL": "",
        "id": 1,
        "jobTitle": "",
        "lastName": "Bloggs",
        "linkedinURL": "",
        "mobile": "",
        "phone": "",
        "twitterURL": ""
    }
}

Agent

{
    "agent": {
        "avatarURL": "https://digitalcrew.teamwork.com/desk/images/avatars/animals/sheep.png",
        "firstName": "Jane",
        "id": 1,
        "lastName": "Agent"
    }
}

Inbox

{
    "inbox": {
        "id": 1,
        "name": "Support",
        "state": "active"
    }
}

Headers

Webhooks include the following headers:

  • X-Desk-Event: The event name of the webhook, e.g ticket.created
  • X-Desk-Signature: The signature generated by Teamwork Desk using your Secret Token for you to determine if the request is genuine.
  • X-Desk-Delivery: The delivery UUID, this is listed in the Recent Deliveries section of your webhook.
  • User-Agent: The version of the webhooks service used to make this request is included in this header.

Verifying

So you can verify that the request comes from Teamwork Desk we include the X-Desk-Signature header. This header includes the HMAC-SHA256 hex encoded signature of the request which was computed using your Secret Token in your webhook settings.

To verify the request you should compute the HMAC hash and compare it against the X-Desk-Signature header, if they match then you know the request was sent from Teamwork Desk. See the examples for a demonstration of this.

Responses

Responses with a status code other than 200 will be considered as a failure, failures will be reattempted 3 times before permanent failure. After multiple permanent failures we will disable your webhook.

Reattempt # Delay (mins)
1 1
2 5
3 10

Examples

Go

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

const secretToken = "bea1ffc4e56d5056b6e0c7ee24b47b5"

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        if r.Method != "POST" {
            http.Error(w, "", http.StatusBadRequest)
            return
        }

        b, err := ioutil.ReadAll(r.Body)
        if err != nil {
            http.Error(w, "", http.StatusInternalServerError)
            return
        }

        if !validSignature(r.Header.Get("X-Desk-Signature"), b) {
            http.Error(w, "", http.StatusBadRequest)
            return
        }

        fmt.Println("Verified Teamwork Desk Webhook:")
        for h, v := range r.Header {
            fmt.Printf("%s: %s\n", h, v[0])
        }
        fmt.Println("-------------------")
        fmt.Println(string(b))
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

func validSignature(sig string, body []byte) bool {
    mac := hmac.New(sha256.New, []byte(secretToken))
    mac.Write(body)
    return sig == hex.EncodeToString(mac.Sum(nil))
}

PHP

<?php

define('SECERT_TOKEN', 'bea1ffc4e56d5056b6e0c7ee24b47b5');

$body = file_get_contents('php://input');
$sig = hash_hmac('sha256', $body, SECERT_TOKEN, false);
if ($sig !== $_SERVER['HTTP_X_DESK_SIGNATURE']) {
    error_log('Bad signature');
    http_response_code(400);
    exit;
}

error_log('Verified Teamwork Desk Webhook Event: ' . $_SERVER['HTTP_X_DESK_EVENT']);
error_log($body);