The Networked Help Desk 1.0 Protocol

Abstract

The Networked Help Desk Protocol provides a method by which organizations can communicate across various help desks, bug trackers, and other ticketing systems.

Status of This Memo

This document is not an Internet Standards Track specification; it is published for informational purposes.

This document is a product of the members of NetworkedHelpDesk.org. It represents the consensus of those members. It has not yet received public review and should be considered a draft only.

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at http://networkedhelpdesk.org/rfc.

Copyright © 2011 Zendesk, Inc. and the persons identified as the document authors. All rights reserved.

Table of Contents

(To be filled in)

Introduction

An early version of the Networked Help Desk Protocol was originally created by engineers at Zendesk to enable customers to share tickets among Zendesk help desks. It quickly became apparent that the same protocol could connect any help desk, bug tracker, or other ticketing system.

This document provides informational documentation of the workings of version 1.0 of the protocol.

Terminology

Ticket
A typical help desk terminology for a user-submitted question, problem, etc. This is synonymous with case, story, issue, etc.
Ticket sharing
the notion of actually taking a ticket (or case, story, issue, etc) and sending it elsewhere, be it another help desk, bug tracker or any other software.
Sender
someone sending tickets to another location.
Receiver
someone receiving tickets from a Sender. Note that either the Sender or Receiver may actually be on the same software provider, or completely different providers.
Agreement
a set of permissions (explained below) created by a Sender in order to control what it is the Receiver can actually do with tickets that the Sender shares.
Agreement Invite
the action of sending an invitation to a potential Receiver that outlines the permissions of the agreement for them to either accept or decline.
Full delegation
When an agreement exists between a Sender and a Receiver, there are a set of permissions which restricts or enables the Receiver to perform certain actions on tickets the Sender shares. In the case of full delegation the Receiver can make both public comments (the customer will see these comments) and private comments (the customer won’t see these comments) on a ticket, and the status of a ticket will always be synced.
Partial delegation
Unlike full delegation, the Receiver is unable to make public comments at all, and is restricted to making only private comments. Similarly, the status is not synced across Receiver and Sender accounts.
Tag syncing
When creating an agreement, the Sender may choose to also send over the tags contained on a shared ticket, over to the Receiver. This then means if either Sender or Receiver changes the tags on a shared ticket, it will be reflected on both ends. UUID
A Universally Unique IDentifier
Access Key
A secret key which grants a help desk access to interact with tickets in another help desk. Do not share this key with anyone.
Sharing URL
The URL under which all other sharing URLs reside, e.g. http://support.example.org/sharing/.
X-Ticket-Sharing-Token
A combination of UUID and Access Key combined to form a single string, i.e. UUID:Access Key.
X-Ticket-Sharing-Version
A version number representing the version of the ticket sharing protocol used in a request.
X-Ticket-Sharing-Versions
A semicolon-separated list of version numbers representing the versions of the ticket sharing protocol that the server supports.

</section> <section markdown="block">

Example

Sally is in charge of customer support for MondoCam (sender), an enthusiast photography supply store. She receives a help ticket via email from Seth asking about some trouble he’s having purchasing a new wide-angle lens for his camera. Sally knows discovers that there have been some outages at MondoCam’s hosting provider, UltraHost (receiver). She sends the ticket on to their help desk to ask whether the outages could have been the cause of Seth’s trouble.

POST /sharing/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb HTTP/1.1
Host: support.ultrahost.com
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

{
  "uuid": "8c0c8a19a3c598be24047eee940c7ce4c259d1bb",
  "subject": "Cannot complete purchase",
  "requested_at": "2010-11-24 14:13:54 -0800",
  "status": "open",
  "requester": {
    "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
    "name": "Seth User"
  },
  "comments": [
    {
      "uuid": "59e8c53b5c39716e510127e004cc01fc7aaaecd2",
      "author": {
        "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
        "name": "Seth User"
      },
      "body": "Hello MondoCam. I seem to be having some trouble completing a purchase. Can you help?"
      "authored_at": "2010-11-24 14:13:54 -0800"
    },
    {
      "uuid": "4a7542fc9267d94a532ab7221726bd81f087fc87",
      "author": {
        "uuid": "127fabf85992fd86091e5e449aa531d6c2eb8116",
        "name": "Sally Agent"
      },
      "body": "Hello Joe. I'm sorry to hear you're having trouble.\
               I think the cause might be with our hosting provider,
               UltraHost. Let me check with with.",
      "authored_at": "2010-11-24 14:25:23 -0800"
    }
  ]
}

Mika, a support engineer at UltraHost, receives the ticket and finds out that the outage did in fact coincide with Seth’s troubles. Because MondoCam and UltraHost have Full Delegation enabled on their ticket- sharing Agreement, Mika can respond directly to Seth. She writes a note apologizing for the trouble and sets the ticket to “solved.” The UltraHost help desk sends an HTTP request back to the MondoCam help desk, which updates the ticket to “solved” and emails Seth with Mika’s response.

PUT /sharing/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb HTTP/1.1
Host: mypartner.com
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

{
  "uuid": "8c0c8a19a3c598be24047eee940c7ce4c259d1bb",
  "status": "solved",
  "current_actor": {
    "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
    "name": "Mika"
  },
  "comments": [
    {
      "uuid": "184313b9e6347dcade7245123b330af2a5b82a86",
      "author": {
        "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
        "name": "Mika"
      },
      "body": "Hi, Seth. It looks like Sally was right. This one's our\
               fault. I'm really sorry about that. The good news is that\
               everything should be back to normal, so you can try your\
               purchase again now."
      "authored_at": "2010-11-24 15:14:24 -0800"
    }
  ]
}

Notational Conventions

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC2119.

Business Rules

Agreements

uuid
a 40-digit hexidecimal number, expressed as a string. Immutable. Required.
access_key
a 40-digit hexidecimal number, expressed as a string. Required.
status
one of "pending", "accepted", "declined", and "inactive". Required. New agreemens MUST have the value "pending".
deactivated_by
one of "sender", "receiver", "" (the empty string), and null. MUST be "sender" or "receiver" if status is "inactive". Must be "" or null otherwise.

Changes to an agreement’s status are constrained as follows:

  • the receiver may change the status from pending to accepted to accept it or to declined to decline it
  • either party may change the status from accepted or declined to inactive to cancel it, but must set the deactivated_by field to sender or receiver as appropriate
  • the party designated by deactivated_by (if any) may change the status from inactive to accepted to reactivate it, but must set the deactivated_by field to "" (the empty string) or null when doing so
  • no other changes to status are allowed

Tickets

uuid
a 40-digit hexidecimal number, expressed as a string. Immutable. Required.
status
one of "open", "pending", and "solved". Required.
subject
any string of length greater than zero. Required.
requested_at
a date expressed in XML-schema format as a string. Immutable. Required.
requester
an actor (see below). Immutable. Required.
comments
an array of comments (see below).

</section> <section markdown="block">

Actors

uuid
a 40-digit hexidecimal number, expressed as a string. Immutable. Required.
name
any string of length greater than zero. Required.

</section> <section markdown="block">

Comments

uuid
a 40-digit hexidecimal number, expressed as a string. Immutable. Required.
author
an actor (see above).
body
a string of length greater than zero. Required.
authored_at
a date expressed in XML-schema format as a string. Required.
attachments
an array of attachments (see below).

</section> <section markdown="block">

Attachments

url
the URL of the attachment. Required. Making a GET request to the attachment url MUST NOT require any additional authentication. If privacy is needed, it is recommended that the url include an access token and use the https scheme.
filename
a string of length greater than zero. Require

HTTP & REST Conventions

Encoding and Formatting

All servers MUST advertise an Accept-Charset that includes UTF-8 and an Accept-Encoding that includes application/json. Servers and clients MAY negotiate other characters sets and encodings.

Verbs

To create a resource, the requester makes a POST request to the resource URL and includes the full resource in the body. To update a resource, the requester makes a PUT request to the resource URL and need only include those fields that are to be changed.

JSON

When representing resources as JSON, all requests MUST use the following formats:

Agreement

{
  "uuid": "23538de2af57572219a037c98aa4623a6767a498",
  "name": "Sender Company Name",
  "receiver_url": "http://example.org/sharing",
  "sender_url": "http://mycompany.net/shared",
  "access_key": "08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f",
  "status": "inactive",
  "deactivated_by": "sender"
}

Ticket

{
  "uuid": "8c0c8a19a3c598be24047eee940c7ce4c259d1bb",
  "status": "pending",
  "current_actor": {
    "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
    "name": "Agent Name"
  },
  "comments": [
    {
      "uuid": "184313b9e6347dcade7245123b330af2a5b82a86",
      "author": {
        "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
        "name": "Agent Name"
      },
      "body": "Hi, I am the agent that will help you."
      "authored_at": "2010-11-24 15:14:24 -0800"
    }
  ]
}

REST Endpoints

Ticket Sharing Protocol Information

A server that wishes to accept ticket sharing agreements and shared tickets MUST respond with a 200 OK to a GET to its sharing URL. It MUST include the X-Ticket-Sharing-Versions response header with a semicolon-separated list of the versions of the ticket-sharing protocol that it supports. For example:

GET /sharing HTTP/1.1
Host: support.example.org

=====

HTTP/1.1 200 OK
X-Ticket-Sharing-Versions: 1

The receiver MAY include a body with additional information about its implementation of the ticket-sharing protocol.

Creating a Ticket Sharing Agreement

Before a sender and a receiver can share ticket, they must set up a ticket-sharing agreement. To do so, the sender generates a uuid and an access_key and makes a POST request to <receiver URL>/agreements/<agreement UUID>.

Request

  • The UUID suffix of the request URL MUST match the uuid property of the reqeust body.
  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1.
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example
POST /sharing/agreements/23538de2af57572219a037c98aa4623a6767a498 HTTP/1.1
Host: support.example.org
X-Ticket-Sharing-Version: 1

{
  "uuid": "23538de2af57572219a037c98aa4623a6767a498",
  "name": "Sender Company Name",
  "receiver_url": "http://support.example.org/sharing",
  "sender_url": "http://mycompany.net/help/shared",
  "access_key": "08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f",
  "status": "pending"
}

Response

  • If the server does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the server does not allow the requester to create such an agreement, it MUST return a 403 Forbidden response.
  • If any required fields are missing or invalid, the server MUST return a 422 Unprocessable Entity response.
  • If the server can successfully create the agreement, it MUST return a 201 Created response. It SHOULD include a Location header with the URL of the newly-created agreement.
Example
HTTP/1.1 201 Created
X-Ticket-Sharing-Versions: 1
Location: https://support.example.org/sharing/agreements/23538de2af57572219a037c98aa4623a6767a498

Updating a Ticket Sharing Agreement

After it is created, either the party may update the agreement at any time. The sender does so by making a PUT request to <receiver URL>/agreements/<agreement UUID>. The receiver does so by making a PUT request to <sender URL>/agreements/<agreement UUID>. (As is the case for all updates in this specification, the request need only include changed fields.)

Request

  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1.
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example

To deactivate an agreement that is currently accepted, the sender makes the following request and gets the following response:

 PUT /shared/agreements/23538de2af57572219a037c98aa4623a6767a498 HTTP/1.1
 Host: example.org
 X-Ticket-Sharing-Version: 1
 X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

 {
   "status": "inactive",
   "deactivated_by": "sender"
 }

Response

  • If the requester does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the requester does not include an X-Ticket-Sharing-Token header, the receiver MUST return a 401 Authorization Required response with a WWW-Authenticate header that includes the authentication type X-Ticket-Sharing.
  • If the requester includes an invalid X-Ticket-Sharing-Token or one that does not match the agreement requested, the server MUST return a 403 Forbidden response.
  • If no such agreement exists, the server MUST return a 404 Not Found response.
  • If the requester specifies an invalid change to status, attempts to change the agreement’s UUID, or otherwise make the agreement invalid, the server MUST return a 422 Unpocessable Entity response.
Example
HTTP/1.1 200 OK
X-Ticket-Sharing-Versions: 1

Retrieving a Ticket Sharing Agreement

Any server MAY support GET requests to an agreement URL. If it does not, it MUST respond to any GET to an agreement URL with a 406 Method Not Supported (or another 4xx status code, depending on the request headers). If it does support GETs, it MUST do so as follows:

Request

  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1.
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example
GET /shared/agreements/23538de2af57572219a037c98aa4623a6767a498 HTTP/1.1
Host: example.org
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

Response

  • If the requester does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the requester does not include an X-Ticket-Sharing-Token header, the receiver MUST return a 401 Authorization Required response with a WWW-Authenticate header that includes the authentication type X-Ticket-Sharing.
  • If the requester includes an invalid X-Ticket-Sharing-Token or one that does not match the agreement requested, the server MUST return a 403 Forbidden response.
  • If no such agreement exists, the server MUST return a 404 Not Found response.
  • Otherwise, the server MUST return a 200 OK response with an appropriate body.
Example
HTTP/1.1 200 OK
X-Ticket-Sharing-Versions: 1
Content-Length:285
Content-Type:application/json; charset=utf-8

{
  "uuid": "23538de2af57572219a037c98aa4623a6767a498",
  "name": "Sender Company Name",
  "receiver_url": "http://support.example.org/sharing",
  "sender_url": "http://mycompany.net/help/shared",
  "access_key": "08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f",
  "status": "pending"
}

Sharing a Ticket

Once an agreement has been accepted, the sender may share a ticket with the receiver by making a POST request to <receiver URL>/tickets/<ticket UUID>.

Request

  • The UUID suffix of the request URL MUST match the uuid property of the reqeust body.
  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example
POST /help/shared/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb HTTP/1.1
Host: mycompany.net
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

{
  "uuid": "8c0c8a19a3c598be24047eee940c7ce4c259d1bb",
  "subject": "Trial expiry time mismatch",
  "requested_at": "2010-11-24 14:13:54 -0800",
  "status": "open",
  "requester": {
    "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
    "name": "Joe User"
  },
  "comments": [
  {
    "uuid": "59e8c53b5c39716e510127e004cc01fc7aaaecd2",
    "author": {
      "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
      "name": "Joe User"
    },
    "body": "Hello Company Support, I would like some help."
    "authored_at": "2010-11-24 14:13:54 -0800"
  },
  {
    "uuid": "4a7542fc9267d94a532ab7221726bd81f087fc87",
    "author": {
      "uuid": "127fabf85992fd86091e5e449aa531d6c2eb8116",
      "name": "Agent Smith"
    },
    "body": "Hello Joe, How can I help you?",
    "authored_at": "2010-11-24 14:25:23 -0800"
  }]
}

Response

  • If the requester does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the requester does not include an X-Ticket-Sharing-Token header, the server MUST return a 401 Authorization Required response with a WWW-Authenticate header that includes the authentication type X-Ticket-Sharing.
  • If the requester includes an invalid X-Ticket-Sharing-Token, the server MUST return a 403 Forbidden response.
  • If any required fields are missing or invalid, the server MUST return a 422 Unprocessable Entity response.
  • If the server can successfully create the ticket, it MUST return a 201 Created response. It SHOULD include a Location header with the URL of the newly-created ticket.
Example
HTTP/1.1 201 Created
X-Ticket-Sharing-Versions: 1
Location: https://support.example.org/sharing/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb

Updating a Ticket

After it has been shared, either the party may update a ticket at any time. The sender does so by making a PUT request to <receiver URL>/tickets/<ticket UUID>. The receiver does so by making a PUT request to <sender URL>/tickets/<ticket UUID>. (As is the case for all updates in this specification, the request need only include changed fields.)

Request

  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example

To add a comment to the ticket, the receiver would make the following request:

PUT /help/shared/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb HTTP/1.1
Host: mycompany.net
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

{
  "current_actor": {
    "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
    "name": "Agent Name"
  },
  "comments": [
    {
      "uuid": "184313b9e6347dcade7245123b330af2a5b82a86",
      "author": {
        "uuid": "7e806b7d962be5afdafcd95d9d53498af2ea5b1f",
        "name": "Agent Name"
      },
      "body": "Hi, I am the agent that will help you."
      "authored_at": "2010-11-24 15:14:24 -0800"
    }
  ]
}

Response

  • If the requester does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the requester does not include an X-Ticket-Sharing-Token header, the server MUST return a 401 Authorization Required response with a WWW-Authenticate header that includes the authentication type X-Ticket-Sharing.
  • If the requester includes an invalid X-Ticket-Sharing-Token, the server MUST return a 403 Forbidden response.
  • If any required fields are missing or invalid, the server MUST return a 422 Unprocessable Entity response.
  • If the server can successfully create the ticket, it MUST return a 201 Created response. It SHOULD include a Location header with the URL of the newly-created ticket.
Example
HTTP/1.1 200 OK
X-Ticket-Sharing-Versions: 1

Retrieving a Ticket Sharing Agreement

Any server MAY support GET requests to a ticket URL. If it does not, it MUST respond to any GET to a ticket URL with a 406 Method Not Supported (or another 4xx status code, depending on the request headers). If it does support GETs, it MUST do so as follows:

Request

  • The requester MUST include a X-Ticket-Sharing-Version header with the value 1.
  • The requester MUST include a X-Ticket-Sharing-Token header with the value <agreement_uuid>:<access_key>.
Example
GET /shared/tickets/8c0c8a19a3c598be24047eee940c7ce4c259d1bb HTTP/1.1
Host: example.org
X-Ticket-Sharing-Version: 1
X-Ticket-Sharing-Token: 23538de2af57572219a037c98aa4623a6767a498:08a479474fc0c3fabfa2b7906f0ce5e55ad2d78f

Response

  • If the requester does not include an X-Ticket-Sharing-Version header or the server does not support the version of the ticket-sharing protocol that the requester has specified, it MUST return a 412 Precondition Failed response.
  • If the requester does not include an X-Ticket-Sharing-Token header, the receiver MUST return a 401 Authorization Required response with a WWW-Authenticate header that includes the authentication type X-Ticket-Sharing.
  • If the requester includes an invalid X-Ticket-Sharing-Token or one that does not match the ticket requested, the server MUST return a 403 Forbidden response.
  • If no such ticke exists, the server MUST return a 404 Not Found response.
  • Otherwise, the server MUST return a 200 OK response with an appropriate body.
Example
 HTTP/1.1 200 OK
 X-Ticket-Sharing-Versions: 1
 Content-Length:869
 Content-Type:application/json; charset=utf-8

 {
   "uuid": "8c0c8a19a3c598be24047eee940c7ce4c259d1bb",
   "subject": "Trial expiry time mismatch",
   "requested_at": "2010-11-24 14:13:54 -0800",
   "status": "open",
   "requester": {
     "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
     "name": "Joe User"
   },
   "comments": [
     {
       "uuid": "59e8c53b5c39716e510127e004cc01fc7aaaecd2",
       "author": {
         "uuid": "9b80c1331d9d746c493a8b8e6d3014347469615e",
         "name": "Joe User"
       },
       "body": "Hello Company Support, I would like some help."
       "authored_at": "2010-11-24 14:13:54 -0800"
     },
     {
       "uuid": "4a7542fc9267d94a532ab7221726bd81f087fc87",
       "author": {
         "uuid": "127fabf85992fd86091e5e449aa531d6c2eb8116",
         "name": "Agent Smith"
       },
       "body": "Hello Joe, How can I help you?",
       "authored_at": "2010-11-24 14:25:23 -0800"
     }
   ]
 }

Contents