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 Notice
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
andAccess 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), andnull
. MUST be"sender"
or"receiver"
ifstatus
is"inactive"
. Must be""
ornull
otherwise.
Changes to an agreement’s status
are constrained as follows:
- the receiver may change the
status
frompending
toaccepted
to accept it or todeclined
to decline it - either party may change the
status
fromaccepted
ordeclined
toinactive
to cancel it, but must set thedeactivated_by
field tosender
orreceiver
as appropriate - the party designated by
deactivated_by
(if any) may change thestatus
frominactive
toaccepted
to reactivate it, but must set thedeactivated_by
field to""
(the empty string) ornull
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 theurl
include an access token and use thehttps
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 value1
. - 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 value1
. - 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 aWWW-Authenticate
header that includes the authentication typeX-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 value1
. - 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 aWWW-Authenticate
header that includes the authentication typeX-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 value1
- 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 aWWW-Authenticate
header that includes the authentication typeX-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 value1
- 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 aWWW-Authenticate
header that includes the authentication typeX-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 value1
. - 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 aWWW-Authenticate
header that includes the authentication typeX-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"
}
]
}