Skip to content
vladyka edited this page Nov 23, 2023 · 424 revisions

Google Support Group

https://groups.google.com/forum/#!forum/sherpadesk-api

API Playground

https://documenter.getpostman.com/view/4454237/apisherpadeskcom-playground/RW8AooQg#7e0d598b-9b35-8b66-c850-81ae325bb5fd

Service URL Endpoint

https://api.sherpadesk.com/

API URL Structure

Many Objects
GET https://{orgKey}-{instanceKey}:{APIToken}@api.sherpadesk.com/{objects}?query=Param=x

Single Object
GET https://{orgKey}-{instanceKey}:{APIToken}@api.sherpadesk.com/{object}/{ID}?query=Param=x

**Important** Filters or Magic query applied only on current data page. Please use search parameters to get correct results.

API Calls Meta Data

http://api.sherpadesk.com/metadata

Definitions

Organization - SherpaDesk accounts are organized by Organization/Instance. 99% of the time you only have one organization and one instance.

Instances - 99% of SherpaDesk clients should only have 1 Org and 1 Instance. By default this instance is named "Main". If for some reason you are a larger organization you might have multiple instances like: HR, Accounting,IT, ....

Authenticate

Basic Authentification

Pass your email address and password to retrieve your api token. This is the same api token you can view in the web app by navigating to "Your Profile."

GET https://api.sherpadesk.com/login 
Base64Encode: username:password

headers :
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Response Status: 200 OK

{
    "api_token" : "teo957f8gmae0snzzzce5ma0i1cgax6j",
}

Login with Google ID

It's possible to use Google OpenId 2.0 schema. To get out API token you need to do request

POST api.sherpadesk.com/api/auth/googleopenid

Response Status: 200 OK

{
    "Location" : "m.sherpadesk.com?t=teo957f8gmae0snzzzce5ma0i1cgax6j",
}

Retrieve Orgs and Instances

Use HTTP Basic Authentication in the format = x:api_token Request

GET /organizations/

e.g. https://x:{api_token}@api.sherpadesk.com/organizations/

Response

[
    {
        "key" : "fr2fop",
        "name" : "bigWebApps",
        "instances" : [
            {
                "key" : "f2fs33",
                "name" : "Main Default Instance 1"
            }
        ]
     }
 ]

Create Organization

Request

POST /organizations/

e.g. https://api.sherpadesk.com/organizations/

Parameters:

name - should be 3 or more chars

email

url - should be between 3 and 20 chars

firstname

lastname

password - Password must be alphanumeric with at least 5 characters

password_confirm

how - how did you hear about us, Goggle etc.

is_force_registration -  if is_force_registration = false, then if email already exists in system, you'll get message "email already registered" so you need to give a choice for user, if he wants to login or create new org, like we have on https://app.sherpadesk.com/mc/signuporg.aspx page. If is_force_registration = true, even if email already exists in system, you'll register new organization.

is_force_redirect - automatically redirects after signup (used in widget - http://m.sherpadesk.com/widget.html)

provider - Google, Salesforce

iiid  - invite Instance Guid 

note - Note

industry - IT, other

techs_number  - Number of techs in Organization

Errors on Org Creation

403 - "Url already exists." if url is reserved

409 - "User already have one registered organization. Please login OR set is_force_registration=true to continue." - if organization already exists

GET PUT POST DELETE Operations

###GET 1 Object

GET /tickets/26f23g 
GET /tickets/1001   
GET /accounts/j738d3

###GET Many Objects

GET /tickets?status=open
GET /tickets?status=open&status=closed     {status open or closed}
GET /accounts?name=Acme&status=active      {name is Acme AND status is active}
GET /tickets?magic=xxxxx                   {magic command xxxxx, more in the docs on this}

###POST Create New Object

POST /tickets
POST /accounts

###PUT Update Existing Object

PUT /tickets/1001
PUT /tickets/27fh2d
PUT /invoices/h263f2

###PUT Special Action Special Actions like Merging a Ticket or Sending an Invoice to a customer.

PUT /invoices/h263f2   { "action" : "sendEmail" }
PUT /tickets/23f2s3     { "action" : "merge" , "TicketInto" : "72f23f" }

###DELETE Delete ONE Object

DELETE /tickets/1001
DELETE /accounts/fhwfe2

All Other Follow-Up Requests

Use HTTP Basic Authentication in the format = org_key-instance_key:api_token

Authorization header should be encoded in Base64Encode:

Authorization: Basic QWxhZGRpsjkgdkfjghdkjfdkfsdjbjpvcGVuIHNlc2FtZQ==

In browser Request

https://{org_key}-{instance_key}:{api_token}@api.sherpadesk.com/tickets?status=closed&priority=3

see examples here:  https://documenter.getpostman.com/view/4454237/apisherpadeskcom-playground/RW8AooQg#7e0d598b-9b35-8b66-c850-81ae325bb5fd

JQUERY Examples

We use real test user data. So those scripts really work on production.

See more examples here: https://documenter.getpostman.com/view/4454237/apisherpadeskcom-playground/RW8AooQg#7e0d598b-9b35-8b66-c850-81ae325bb5fd

GET

 // Get ticket info in browser to check
 //  https://ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf@api.sherpadesk.com/tickets/111?format=json       

 $.ajax({
    type: 'GET',
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 
                             'Basic ' + btoa('ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf'));
        },
    url: 'http://api.sherpadesk.com' + '/tickets/111',
    data: {}, 
    dataType: 'json',
    success: function (d) {
             alert('Success! Got ticket ' + d.subject);  
    },
    error: function (e, textStatus, errorThrown) {
             alert(textStatus);
    }
 });

POST

 // Get ticket info in browser to check
 // https://ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf@api.sherpadesk.com/tickets/111?format=json        

 $.ajax({
    type: 'POST',
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 
                             'Basic ' + btoa('ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf'));
        },
    url: 'http://api.sherpadesk.com' + '/tickets/111',
    data: {"note_text" : "test post at " + new Date().toString() }, 
    dataType: 'json',
    success: function (d) {
             alert('Success! Posted response to ticket with key bjna5t');  
    },
    error: function (e, textStatus, errorThrown) {
             alert(textStatus);
    }
 });      

PUT

 // Get ticket info in browser to check
 // https://ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf@api.sherpadesk.com/tickets/111?format=json       

 $.ajax({
    type: 'PUT',
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 
                             'Basic ' + btoa('ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf'));
        },
    url: 'http://api.sherpadesk.com' + '/tickets/111',
    data: {"note_text" : "status changed to CLOSED at " + new Date().toString(),
			        "status" : "closed" }, 
    dataType: 'json',
    success: function (d) {
             alert('Success! Closed ticket with key bjna5t');  
    },
    error: function (e, textStatus, errorThrown) {
             alert(textStatus);
    }
 });         

DELETE

 // First - Get List of Todos
 // https://ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf@api.sherpadesk.com/tickets/111/todos

 $.ajax({
    type: 'DELETE',
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 
                             'Basic ' + btoa('ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf'));
        },
    url: 'http://api.sherpadesk.com' + '/todos/baae8841c60f4b3dbffa33053c90aced',
    data: {}, 
    dataType: 'json',
    success: function (d) {
             alert('Success! Todo baae8841c60f4b3dbffa33053c90aced deleted');  
    },
    error: function (e, textStatus, errorThrown) {
             alert(textStatus);
    }
 });  

VB script GET Examples

We use real test user data. So those scripts really work on production.

Public Function httpGET() As String
Dim oHttp As Object
Set oHttp = CreateObject("Microsoft.XMLHTTP")
Call oHttp.Open("GET", "https://api.sherpadesk.com/time?limit=25&format=json", False)
    oHttp.SetRequestHeader "Content-Type", "application/json"
    oHttp.SetRequestHeader "Accept", "application/json"
    ' need to base64 encode your auth data "ncg1in-8d1rag:5nuauzj5pkfftlz3fmyksmyhat6j35kf" you can use this site https://www.base64encode.org
    oHttp.SetRequestHeader "Authorization", "Basic bmNnMWluLThkMXJhZzo1bnVhdXpqNXBrZmZ0bHozZm15a3NteWhhdDZqMzVrZg=="
Call oHttp.Send("")
httpGET = oHttp.ResponseText
Set oHttp = Nothing
End Function

PowerShell Examples

PowerShell implementation https://github.com/ThePoShWolf/PSSherpaDesk (creadits to Anthony Howell | Howell IT (anthony@howell-it.com))

I found some info: https://pallabpain.wordpress.com/2016/09/14/rest-api-call-with-basic-authentication-in-powershell/

you need to encode your creds to base64 first

example:

Invoke-WebRequest -Uri https://api.sherpadesk.com/tickets  -Method Get -Header @{Authorization = "cHhvcTUteWljNHNlOmtuZHNma2pzZGhma2pzaGRrZmhrc2hkZnM="} -UseBasicParsing

where cHhvcTUteWljNHNlOmtuZHNma2pzZGhma2pzaGRrZmhrc2hkZnM= is encoded string of "pxoq5-yic4se:kndsfkjsdhfkjshdkfhkshdfs"

you need your string with correct token.

I personally use this site to encode

https://www.base64encode.org/

C# Examples

We use real test user data. So those scripts really work on production.

GET

string xApiToken = Variables.ApiToken;

string xOrgKey = Variables.OrgKey;

string xInstanceKey = Variables.InstanceKey;

string credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(xOrgKey + "-" + xInstanceKey + ":" + xApiToken));

HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create(“http://api.sherpadesk.com/tickets?format=json&page=0”);

httpWReq.Headers[HttpRequestHeader.Authorization] = string.Format("Basic {0}", credentials);

HttpWebResponse httpWResp = (HttpWebResponse)httpWReq.GetResponse();

Response formats

You can get data in those formats:

  • json (default)
  • xml
  • csv
  • jsv

Example call:

 https://api.sherpadesk.com/tickets?format=xml

JSONP CallBacks

Callbacks are needed for users implementing JSONP. Using the “callback” parameter you are instructing our web service end point to wrap the json output in a javascript function. Remember JSONP only supports HTTP GET requests.

?callback=FUNC_NAME
 
e.g. 
https://api.sherpadesk.com/tickets/1?callback=HelloWorld

a standard JSON Response

{"symbol" : "IBM", "price" : 91.42}

a JSONP Response with CallBack

HelloWorld({"symbol" : "IBM", "price" : 91.42})

Pseudo Unique Values | Key

Pseudo Unique Keys are used on some objects and resources in place of integer or guid values. Pseudo Unique values are 6 character strings consisting of random alpha numeric values 0-9 and lower case letters a-z (excluding “o”). e.g. jkl2dz , 23jrea or ticket number There are 35 character combinations.

{
    "key" : "2f234h"
}

Pages

Limits and Pages

Recently we had some api clients requesting large numbers of records frequently and it was effecting the entire system performance. So API requests are limited to 600 requests per hour.

API requests which return multiple objects are limited to 25 records per page (maximum limit is 250 records per page).
Page numbers start at 0.
If your results contain 25 objects you should inspect the next page for additional objects.
Use the query string “page=1″.

/tickets/?page=1     {default returns up to 25 records}

/tickets/?page=1&limit=50

We introduce Content-Range header which shows current array of items returned and total count. You can use it for navigation. It contains {start_index(start at 0)} - {end_index} / { total_count}

Important: If end_index is reached total_count-1 items, it means you got all records and paging finished.

Examples:

items 1-1/0 { means returned no records, cause  total_count = 0 }

items 0-9/100 { means returned 10 records (from 0 to 9) with total_count = 100 }

items 10-99/100 { means returned all last records, cause total_count = 100 and end_index is 99 }

Content-Range Header

Bulk data operations and Database backups

We introduce new Beta feature to get any amount of data from API. You can export any number of records in CSV format. Just add ?format=csv and you can use any limits (even &limit=100000)

Ready for Assets, Users, Tickets, Timelogs, Locations and Accounts

This feature is open for testing now.

To follow 302 redirect please use:

$ curl -L [url]

Running this command will automatically handle any 3XX redirects and will retrieve whatever data is returned by the resulting URL. (https://stackabuse.com/follow-redirects-in-curl/)

High DTU limit and server protection from DDOS attack

We allow only 600 requests per hour. If servers has normal load (DTU < 30%.), we dont limit requests.

But there are time periods, when users do a lot of heavy requests. So we need to protect our servers from DDOS attack. When we detect high load on Database, we add High DTU limit and add additional limit for frequent requests. You can see it on presence of X-Highdtu-Mode: header. More value is, servers are more overloaded.:

Response Headers: X-Highdtu-Mode: 5

We rate by Org key. We DO apply it only to:

"GET", "POST", "PUT", "DELETE" requests

We DON't apply request rate :

HEAD or OPTIONS requests and ANY actions "ping", "config", "login", "organizations"

We add WAIT seconds to each request with this formula:

* single item: dtu*1 = 1 - 5 Seconds
* group of items:  dtu * 5 = 5 – 50 seconds

If servers are in High DTU mode (overloaded), we delay group of items requests for 25 seconds and item request for 5 sec.

Cache Response

We cache large responses to protect our system and supply results for same repeated requests.

Large requests (>100 items) cached for longer time (1-2 hours), small requests (less than 100 items) cached for small time (1-10 minutes).

In case you need to get fresh copy of data, you can add clear cache parameter (c=1):

/tickets?c=1

Sorting

API requests usually return objects sorted by Date in Descending order. You can choose other options. Use the query string parameters “sort_by=key″ and "sort_order=asc" or "sort_order=desc". You can use any existing parameter name, like "name", "date", "number".

/tickets?sort_by=tech&sort_order=asc        {result with ticket list sorted by tech lastname in ascending order}

Error Messages

Details of error or missing data can be found in Status Description.

HTTP/1.1 400 Missing the user or class to transfer the ticket.
Content-Type: application/json
Content-Length: xxxx

HTML Return Codes

General Codes

1xx – Informational: Request received, continuing process.

2xx – Success: Action successfully received, understood, and accepted.

3xx – Redirection: Client must take additional action to complete the request.

4xx – Client Error: Request contains bad syntax or cannot be fulfilled

5xx – Server Error: Server failed to fulfill an apparently valid request.

Specific Codes

200 OK. Represents a successful transaction

201 Created & Location. Used during POST operation to represent a successful transaction and return the absolute URI of the new resource in the HTTP Location header.

204 No Content. Request was valid, no content is returned. Empty search results.

400 Bad Request. The request was invalid. An accompanying error message will explain the reason.

401 Unauthorized. Authentication were missing or incorrect.

403 Forbidden. The request was understood, but it has been refused. An accompanying error message will explain the reason.

404 Not Found. The URI requested is invalid or the resource requested does not exist

405 Method Not Allowed. The HTTP Method is not allowed on the resource. For example, if you attempt to post to URL which does not support POST.

420 Rate Limit. Your api key is being rate limited.

500 Internal Server Error. Something is broken. Please post to the forum for investigation.

502 Bad Gateway. Service is in a known down state or being upgraded.

Developer Key

App Keys are free and easy to obtain. Currently email support@bigwebapps.com to obtain an app key, include: developer name, email, company name, company website, phone, company email. The App Key uses the same 6 character system we use for Pseudo Unique values. e.g. hsy2sd2

HTTP Verbs

GET

Safe, Idempotent implied.

POST

Non Idempotent, multiple requests can generate duplicate objects. The ID (int/guid) is generated by the server. The location of the object is returned as part of the response. Most similar to CRUD – CREATE statement.

PUT

Idempotent, multiple identical requests should have the same effect. The ID (int/guid) is generated client side and specified in the data transferred to the server. The resource is placed in its final position during the PUT request. Most similar to CRUD – UPDATE statement. If the object exists, replace the entire object with the uploaded data.

DELETE

Idempotent, multiple identical requests should have the same effect.

Field Naming & Formats

###Bit – Boolean Field names can have present or past tense and have the prefix “is_“. e.g. is_active, is_enabled, is_created

Values are 1 (true), 0 (false), “null” (null)

###Dates | no time Format is YYYY-MM-DD

Date fields are in past tense and have the suffix “_date”. e.g. created_date, updated_date, sent_date.

###Time Format is YYYY-MM-DD hh:mm:ss.sTZD (refer to W3C ISO 8601)

Time fields are in the past tense and have the suffix “_time”. e.g created_time, updated_time, sent_time

Examples below are the same date and time.

1994-11-05 08:15:30-05:00

1994-11-05 13:15:30Z

Local Time

Important to know, that api return dates in UTC

So if you need to know instance local time you should get also timezoneoffset from /config

User Foreign Key References

Have the suffix “_userid” or "_userkey" to let developer know this is a USER foreign key

e.g. user_userid, tech_userid, created_userid.

or, if using a Pseudo Key, will have the suffix "_userkey"

e.g. user_userkey, tech_userkey, created_userkey

Objects

/accounts
/classes    
/config  (need to retrieve current instance time_zone_offset, is_location_tracking etc)    
/profile    
/articles    (kb articles)
/activity (last 25 activities in department)
/projects
/todos
/invoices
/posts
/levels
/organizations
/login
/ping  - a simple method you can call that will return a "All OK!" as long as everything is good. 
/priorities
/queues
/services - all available services
/tickets
/ticket_actions
/technicians
/time
/files
/locations
/users  (search by email or name)
/payments    (aka staff payments or bills)
/travel_logs
/payments
/assets
/customfields
/prepaid_packs
/contracts
/tax_rates
/folders
/categories
/kb_categories
/kb_levels
/events
/board/lists

Config

Get a organization Config

GET /config   

{
"is_onhold_status": true,
"is_time_tracking": true,
"is_freshbooks": false,
"freshbooks_url": "",
"is_parts_tracking": false,
"is_budget_time": true,
"is_financial_info_for_tech": true,
"is_project_tracking": true,
"is_tech_checkin": true,
"is_restrict_transfer_to_in": true,
"is_todos": true,
"is_unassigned_queue": true,
"is_location_tracking": true,
"is_waiting_on_response": true,
"is_invoice": true,
"is_payments": true,
"is_expenses": true,
"is_show_start_time_on_invoice": true,
"is_add_time_other_techs": true,
"is_class_tracking": true,
"is_travel_costs": true,
"is_creation_categories": false,
"is_creation_categories_required_on_creation": false,
"is_submission_category": false,
"is_show_time_on_ticketlog": false,
"is_priorities_general": true,
"is_confirmation_tracking": false,
"is_custom_fields": true,
"is_resolution_tracking": false,
"is_ticket_levels": true,
"is_ticket_levels_for_users": true,
"is_tech_choose_levels": false,
"is_restrict_tech_escalate": false,
"is_account_manager": true,
"is_require_ticket_initial_post": true,
"is_ticket_require_closure_note": false,
"is_asset_tracking": true,
"is_force_time_on_closing_tickets": false,
"is_allows_tech_to_reopen": true,
"days_allowed_to_reopen": 14,
"days_allowed_to_reopen_user": 14,
"is_transfer_ticket_to_another_user": true,
"is_add_new_user_link": true,
"time_hour_increment": 0,
"time_minimum_time": 0,
"timezone_offset": -4,
"timezone_name": "Eastern Standard Time",
"currency": "$",
"businessday_length": 540,
"is_board_enabled": true,

"user": {
    "account_name": "Account",
    "user_id": 456,
    "unique_id": "",
    "email": "my@example.com",
    "firstname": "SherpaDesk",
    "lastname": "Admin",
    "is_techoradmin": true,
    "is_admin": true,
    "is_limit_assigned_tkts": false,
    "is_useworkdaystimer": true,
    "account_id": 0,
    "time_format": 0,
    "date_format": 0
},

"names": {
    "account": {
        "ap": "Accts",
        "a": "Acct",
        "p": "Accounts",
        "s": "Account"
    },
    "user": {
        "ap": "Users",
        "a": "User",
        "p": "End Users",
        "s": "End User"
    },
    "location": {
        "ap": "Locs",
        "a": "Loc",
        "p": "Locations",
        "s": "Location"
    },
    "tech": {
        "ap": "Techs",
        "a": "Tech",
        "p": "Technicians",
        "s": "Technician"
    },
    "ticket": {
        "ap": "Tkts",
        "a": "Tkt",
        "p": "Tickets",
        "s": "Ticket"
    }
},

"is_customnames": true,

"assets": {
    "unique1_caption": "Bar Code",
    "unique2_caption": "Computer Name",
    "unique3_caption": "",
    "unique4_caption": "",
    "unique5_caption": "",
    "unique6_caption": "",
    "unique7_caption": ""
}

Profile

Get Your Profile

GET /profile  {returns a profile for user id = 12345}

Get Profile of Other User (only for admins)

GET /profile/12345   {returns a profile for user id = 12345}

GET /profile/MyUniqueId   {returns a profile for user id = MyUniqueId }

Update Your Profile (only admin can update any User Profile)

PUT /profile/12345   

{
    "skype" : "skypelogin",
    "phone" : "12-23-123",
    "mobile_phone" : "123-123-12",
    "unique_id" : "new tag",
    "lastname" : "new lastname",
    "firstname" : "new firstname",
    "title" : "new title",
    "organization_name" : "new organization name"
}

Add Alternative Email to Your Profile

POST /profile/altemails   

{
    "emails" : "google@gmail.com, apple@apple.com"
}

Delete Alternative Email from Your Profile

DELETE /profile/altemails   

{
    "emails" : "google@gmail.com"
}

Bulk operations on Update Profiles

Note: Max Limit for one Bulk operation is 100 commands

Bulk list contains list of update requests as list of URLs.

PUT /profile/bulk?format=json

{
    "bulk"	: [
	"profile/123?title=My new title",
	"profile/333?unique_id=909666"
    ]

}

Tickets

Get a List of Tickets

/tickets   {returns a default list of tickets}

/tickets?page=2    {returns page 2 of list of tickets, 25 records per page}

/tickets?status=closed&role=user   {filters the list for the property "status" is closed}

/tickets?start_date=2013-12-23&end_date=2013-12-24

/tickets?search=test* {search by word **test** asterix (*) is needed to search parts of words (testing, etc)}

Get Multiple Tickets

GET:

/tickets/{key},{key},{key}   {returns full ticket details for chosen ticket keys}

POST:

/tickets/keys   {returns full ticket details for chosen ticket keys}

{
  "keys":"{key},{key},{key}"
  "search":"Jon"
}

NOTE:

Save both of the number of calls you are making to API as well as the time it takes to build the report you need to compile.

Filtering of Tickets

You allowed to filter by:

  • status

    /tickets?status=open {returns all open tickets related to user -> from api_key}

  • role

    /tickets?role=user {returns all open tickets where I am the user}

  • account

    /tickets?account=xxx {shows tickets with account containing name or id of account}

  • class

    /tickets?class=xxx {shows tickets with class containing name or id of class}

  • location

    /tickets?location=xxx {shows tickets with location containing name or id of location}

List of Statuses

open  
closed
on_hold
    waiting
    new_messages

i.e. 
/tickets?status=open     {returns all open tickets related to user -> from api_key}
/tickets?status=open,closed    {returns all open OR closed tickets}

All Open Tickets

/tickets?query=all&status=allopen         {magic query, shows all open, all users, all techs, everyone}

Waiting Tickets

/tickets?status=waiting         {shows all waiting tickets}

Post waiting ticket:

POST /tickets/h8s2f2

{
    "note_text": "example",
    "is_waiting_on_post": true
}

List of Roles Modes

user
tech
alt_tech

i.e. 
/tickets?status=open&user={key}&role=user        {returns all open tickets for user with {key} (or logged user) where he is the user}
/tickets?status=open&user={key}&role=user,tech      {returns all open tickets for user with {key} (or logged user) where he is the user OR tech}
/tickets?status=open&user={key}     {all roles, returns all open tickets for user with {key} (or logged user) where he is the user OR tech OR alt_tech}

Ticket Counts

GET /tickets/counts

returns total count of tickets by statuses:

{
  "new_messages":1,
  "open_all":4,
  "open_as_user":5,
  "open_as_tech":5,
  "open_as_alttech":5
  "onhold":1,
  "reminder":2,
  "parts_on_order":0,
  "unconfirmed":0,
  "waiting":2
}

GET /tickets/counts?status=new_messages {returns only count of tickets with specific status}

GET /tickets/counts/{status} (deprecated, but still supported, will be removed next update)

deprecated, but still supported statuses:

"new"

"open"

"total"

Create Ticket

POST /tickets

{
    "status" : "open", //only open allowed
    "subject" : "My Printer is Not Working",
    "initial_post" : "user long message here", 
    "class_id" : 3,
    "account_id" : 654321,
    "location_id" : 0,
    "user_id" : 67890,
    "tech_id" : 12345,
    "attach_assets" : "123, 345", // attach existing Assets ids during ticket creation
    "board_list_id" : "77b764099b854452bf2e470825442677" //add to board list
}

Disable notifications on POST/PUT actions:

Please use n=1 to disable notification on specific action:

PUTT /users/456?n=1 //where n=1 - disable  notifications 

Import New Ticket with Full Data (only for Org Administrators)

POST /tickets/import

{
    "number": 2345 // if number exist you got error, if number = 0, ticket will be with next allowed number
    "status" : "open", // "closed", "onhold" allowed
    "created_time" : ""2014-03-31 11:14:20:00",
    "closed_time" : ""2014-03-31 11:14:20:00",
    "updated_time" : ""2014-03-31 11:14:20:00",
    "subject" : "My Printer is Not Working",
    "initial_post" : "user long message here", 
    "class_id" : 3,
    "account_id" : 654321,
    "location_id" : 0,
    "user_id" : 67890,
    "tech_id" : 12345,
    "attach_assets" : "123, 345", // attach existing Assets ids during ticket creation
    "customfields_xml" : "<root><field id="4724"><caption>www.sherpadesk.com</caption><value>Yes</value></field></root>"
}

Get a Ticket

GET /tickets/h8s2f2   {returns a single ticket}
GET /tickets/12345   {returns a single ticket}

Update a Ticket

PUT /tickets/h8s2f2/

{
    "status" : "closed",
    "note_text" : "some note"
    "level_id" : 3,
    "project_id": 66,
    "class_id" : 3
    "priority_id" : 3
    "account_id" : 3,
    "account_location_id" : 0,
    "is_transfer_user_to_account": "false",
    "is_waiting_on_response" : "true",
    "creation_category_id" : 0,
    "creation_category_name" : "",
    "customfields_xml" : "<root><field id="4724"><caption>www.sherpadesk.com</caption><value>Yes</value></field></root>",
    "default_contract_id" : 0,
    "default_contract_name: "( Not Set )",
    "location_id" : 0,
    "submission_category" : "( Not Set )",
    "tech_id" : 496558,
    "user_id" : 496558,
    "board_list_id" : "77b764099b854452bf2e470825442677" // leave empty to not update, or "0" to reset
}

Update Ticket Custom Fields

PUT /tickets/h8s2f2/

{
   "customfields_xml" : "<root><field id="4724"><caption>www.sherpadesk.com</caption><value>Yes</value></field></root>"
}

Post Response to a Ticket

POST /tickets/h8s2f2/posts (deprecated, but still supported, will be removed next update)

POST /tickets/h8s2f2

{
    "note_text": "example",
    "action": "response",
    "user_id": "111",
    "is_waiting_on_response": "true",
    "is_tech_only": "true",
    "created_date": "2014-03-31 11:14:20:00",
}

Change Subject and Next step on Ticket

POST /tickets/{key}

{
    "action": "subject",
    "subject": "New subject",
    "next_step": "next step",
}

Post Log to a Ticket

POST /tickets/h8s2f2

{
    "note_text": "example", ( Log text )
    "action": "log",
    "note":  "Log Entry"  (optional log type, default is "Log Entry")
}

Post Tech Note to a Ticket

POST /tickets/h8s2f2

{
    "note": "my note",
    "action": "note"
}

Post Workpad to a Ticket

POST /tickets/h8s2f2

{
    "workpad": "my content <h1>test</h1>",
    "action": "workpad"
}

Place a Ticket OnHold

PUT /tickets/h8s2f2/

{
    "status" : "onhold",
    "note_text": "example"
}

Close a Ticket

PUT /tickets/h8s2f2/

{
    "status" : "closed",
    "note_text": "example",
    "is_send_notifications": true,
    "resolved": true,
    "confirmed": true,
    "confirm_note": "confirmed by me"
}

ReOpen a Ticket

PUT /tickets/h8s2f2/

{
    "status" : "open",
    "note_text": "example"
}

PickUp a Ticket

PUT /tickets/h8s2f2/

{
    "action" : "pickup",
    "note_text": "example"
}

Confirm a Ticket

PUT /tickets/h8s2f2/

{
    "action" : "confirm",
    "note_text": "example"
}

Transfer To Tech a Ticket

POST /tickets/{key}

{
    "action": "transfer",
    "note_text": "example",
    "tech_id": "111",
    "keep_attached": false
}

"keep_attached" means, keep the current technician attached plus add the new tech.

Transfer To User a Ticket

POST /tickets/{key}

{
    "action": "transfer",
    "note_text": "example",
    "user_id": "111",
}

Attach Alt_User a Ticket

PUT /tickets/{key}

{
    "user_id": "111, 112, 113" //attach users with ids "111, 112, 113" as Alt_User 
}

Attach Alt_Tech a Ticket

PUT /tickets/{key}

{
    "tech_id": "111, 112, 113" //attach techs with ids "111, 112, 113" as Alt_Tech
}   

Posts

Get Posts

GET /posts?ticket=h8s2f2

Post Response to a Ticket

POST /posts

{
    "ticket": "h8s2f2",
    "note_text": "example",
    "is_waiting_on_response": "true",
    "is_tech_only": "true",
    "files":  multipart/form-data,
    "user_id": "111",
    "created_date": "2014-03-31 11:14:20:00",
}

Levels

Get a List of Levels

/levels

Articles

Get a List of Articles

/articles   {returns a default list of articles}

/articles?search=test* {search by word **test** asterix (*) is needed to search parts of words (testing, etc)}

List of Levels

/kb_levels

1 - "Public Portal"
2 - "Account Specific Portal"
3 - "Private"
4 - "Private - Account Specific"

Events

EventTypes
None = 0,
ToDo = 1,
Event = 2, //(default - all events)
TicketFollowUp = 3,
TicketDue = 4,
TicketClosed = 5,
TicketCreation = 6,
TicketSLACompletion = 7

List of Calendar Events

GET /events?is_calendar=true  //from today to the end of the month

/events?is_calendar=true&start_date=2021-12-1&end_date=2021-12-31 //from start date to the end date

/events?is_calendar=true&account=1&tech=2&date=2014-03-31 11:14:20:00&&end_date=2014-03-31 11:14:20:00 //events with account id, tech id, start_date and end_date

Filter List of Calendar Events

GET /events?is_calendar=true&is_shared=true  //only shared events

/events?is_calendar=true&is_personal =true  //only personal events

/events?is_calendar=true&tech_ids=1,2,3 //only techs with id=1 or id=2 or id=3

/events?is_calendar=true&account_ids=11,22,33 //only accounts with id=11 or id=22 or id=33

/events?is_calendar=true&project_ids=111,221,331 //only projects with id=111 or id=221 or id=331

/events?is_calendar=true&event_type_ids=0,1,2 //only events with type id=0 or id=1 or id=2

/events?is_calendar=true&shared_calendar_ids=11,22,33 //only shared calendar with id=11 or id=22 or id=33

List of Events

GET /events

/events?account=1&tech=2&date=2014-03-31 11:14:20:00&&end_date=2014-03-31 11:14:20:00 //events with account id, tech id, start_date and end_date

List of Ticket Events

GET /events?ticket={key}  //all events of ticket

/events?ticket={key}&event_type_id={id}  //filter events of ticket by event type

Get Event details

GET /events/{event_id}  {returns an Event with event_id=c8801133-a6aa-4419-a2ba-1c2fe2c9ce71}

Get User Event Types

GET /events/types  {returns User defined Types of Event}

Example:

[
   {
      "id":488,
      "name":"Canceled Webinars",
      "color":"#FF0066",
      "is_active":true,
      "is_default":false
   }

]

Create new Event

POST /events

  {
     "account":-1,
     "project":15202,
     "ticket":13500217
     "subject":"test local api",
     "description":"api local desc",
     "tech_id":270,
     "event_type":2,  //default is 2
     "start_date":"2021-12-21T09:26:16.0000000",
     "end_date":"2021-12-22T10:26:16.0000000",
     "user_id":270,
     "shared_event_id":"",
     "event_type_id":17,  //see section Get User Event Types
     "timezone":"FLE Standard Time",
  }

Update an Event

Note: null values mean that we leave the previous value. so if you need to change only dates, please pass only start_date, end_date values

PUT /events/{event_id}

  {
     "account":-1,
     "project":15202,
     "ticket":13500217
     "subject":"test local api",
     "description":"api local desc",
     "tech_id":270,
     "event_type":2,  //default is 2
     "start_date":"2021-12-21T09:26:16.0000000",
     "end_date":"2021-12-22T10:26:16.0000000",
     "user_id":270,
     "shared_event_id":"",
     "event_type_id":17,  //see section Get User Event Types
     "timezone":"FLE Standard Time",
  }

Delete an Event

DELETE /events/{event_id}

Add Events to Timelog

POST /time?event_id=c8801133-a6aa-4419-a2ba-1c2fe2c9ce71

Board Lists

Get Board Lists

GET /board/lists

Create new Board List

POST /board/lists

  {
     "name":"test local api",
     "description":"api local desc",
  }

Update a Board List

POST /board/lists

  {
     "board_list_id" : "66070aecf1f748c5a147aced896e4f9b",
     "name":"test local api",
     "description":"api local desc",
  }

Delete a Board List

DELETE /board/lists

  {
     "board_list_id" : "66070aecf1f748c5a147aced896e4f9b",
  }

Archive/Unarchive a Board List

POST /board/lists/archive

  {
     "board_list_id" : "66070aecf1f748c5a147aced896e4f9b",
     "is_archive" : true // true - to archive, false to unarchive
  }

Add/Remove Ticket, ToDo and Ticket to a Board List

Note: Please use either ticket_id or project_id or todo_item_id to assign(remove) to (from) a Board List

PUT /board/lists

  {
     "board_list_id" : "66070aecf1f748c5a147aced896e4f9b", //_allow empty value and 0_, if you want to delete item from a Board List
     "ticket_id": 10, //integer for ADD or 0(empty) to REMOVE 
     "project_id": 0, //integer for ADD or 0(empty) to REMOVE 
     "todo_item_id": "0", //todo guid id for ADD or 0(empty) to REMOVE 
  }

Articles

Create Article

POST /articles

{
    "date" : "2014-03-31 11:14:20:00", //date created. Default = today date
    "subject" : "My Printer is Not Working",
    "body" : "user long message here", 
    "kb_category_id" : 55, //see /kb_categories
    "account" : 0,
    "kb_alternate_id" : "printer", //Alternate ID
    "kb_search_desc" : "SEO Meta Tag", //SEO Meta Tag
    "tech_id" : 12345,
    "publsh_level_id" : 1 //   see /kb_levels
}

Get a Article

GET /articles/h8s2f2   {returns a single article}

Update a Article

PUT /tickets/h8s2f2/

{
    "status" : "closed",
    "note_text" : "some note"
    "level_id" : 3,
    "project_id": 66,
    "class_id" : 3
    "priority_id" : 3
    "account_id" : 3,
    "account_location_id" : 0,
    "is_transfer_user_to_account": "false",
    "is_waiting_on_response" : "true",
    "creation_category_id" : 0,
    "creation_category_name" : ""
    "customfields_xml" : "<root><field id="4724"><caption>www.sherpadesk.com</caption><value>Yes</value></field></root>"
    "default_contract_id" : 0
    "default_contract_name: "( Not Set )"
    "location_id" : 0
    "submission_category" : "( Not Set )"
    "tech_id" : 496558
    "user_id" : 496558
}

Post Response to a Article

POST /tickets/h8s2f2

{
    "note_text": "example",
    "action": "response",
    "user_id": "111",
    "is_waiting_on_response": "true",
    "is_tech_only": "true",
    "created_date": "2014-03-31 11:14:20:00",
}

Change Subject and Next step on Article

POST /tickets/{key}

{
    "action": "subject",
    "subject": "New subject"
}

KB categories

Get KB categories

GET /kb_categories //get all active

GET /kb_categories?is_active=false //get all 

Get one kb_category

GET /kb_categories/4

Create a KB category

POST /kb_categories

{
    "name": "KB category name",
    "parent_id": 0, //add child KB category to KB category = 0
    "is_active": true
}

Update an KB category name

PUT /kb_categories/{cat_id}

{
    "cat_id": 234, 
    "name": "New Category name",
    "is_active": true
}

Categories

Get Categories

GET /categories  - returns only active categories.

GET /categories?is_active=false - returns all categories

Create a Category

POST /categories

{
    "name": "Category name",
    "is_active": true, //set active
}

Set an Category active/inactive

PUT /categories/{cat_id}

{
    "cat_id": 234, 
    "name": "New Category name", //if name is empty name remains same
    "is_active": true, //true - set active, false - inactivate
}

Classes

Get classes

GET /classes  - returns all active classes.

GET /classes?user=1123 - returns all classes for user with id 1123

GET /classes?class_id=123 - returns child classes for class with id 123

GET /classes?is_active=all - returns all classes 

GET /classes?is_active=false - returns all Inactive classes

Get a classe

GET /classes/1

Get parent classes of class

GET /classes/parent/123 - return parent classes of class with id=123

Create a Class

POST /classes

{
    "name": "Class name",
    "parent_id": 0, //add child class to parent class = 0
    "is_active": true, //set active
    "is_default" : false //set default
}

Set an Class active/inactive

PUT /classes/{class_id}

{
    "class_id": 234, 
    "is_active": true, //true - set active, false - inactivate
}

Delete an Class

DELETE /classes/{class_id}

Priorities

Get Priorities

GET /priorities - returns all priorities.

Get a Priority

GET /priorities/123 - returns a priority with id=123.

Create a Priority (Only for Admins)

POST /priorities

{
    "name": "Priority name",
    "desc": "my priority"
    "is_tech_only": false, //true - Only allow technicians and administrators to choose this priority.
}

Delete an Priority (Only for Admins)

DELETE /priorities/{id}

Folders

Get Folders

GET /folders

Get child folders of folder

GET /folders?folder_id=123 - return child classes of class with id=123

Create a Folder

POST /folders

{
    "name": "Folder name",
    "parent_id": 0, //add child folder to folder = 0
}

Update an Folder name

PUT /folders/{folder_id}

{
    "folder_id": 234, 
    "name": "New Folder name"
}

Delete an Folder

DELETE /folders/{folder_id}

Accounts

Get a List of Accounts

GET /accounts {return list of accounts}

{
    "user" : 1,
    "is_with_statistics" : false,
    "is_open_tickets" : false,
    "is_locations_info" : false,
    "is_watch_info" : false,
    "is_active" : false,
}

Get an Account

GET /accounts/{account_id} {return account info, including contact info, logo, list of files, locations, users, projects, assets, statistic (ticket counts, expenses, etc), custom fields)

{
    "account_id" : 1,
    "is_with_statistics" : false,
    "note" : "Note",
    "is_assets_info" : false,
    "is_locations_info" : false,
    "is_files_info" : false,
    "is_projects_info" : false,
    "is_users_info" : false,
}

Example of account statistics info:

account_statistics : { "ticket_counts":{"open":124,"closed":39,"scheduled":2,"followups":4},

"timelogs":44,

"invoices":9,

"hours":23.5392,

"expenses":39380.7100 }

Create an Account

POST /accounts

{
    "name": "Account Name",
    "email_suffixes": "", //Email Suffixes must like: @acme.com; @microsoft.com
}

Todos

Get single todo

GET /todos/{id}  

Get a List of Todos

GET /todos {return all todos}

Get a Project and Ticket todos

GET /projects/{id}/todos {return todos of project} (deprecated, but still supported, will be removed next update)

GET /tickets/{key}/todos {return todos of ticket} (deprecated, but still supported, will be removed next update)

GET /todos?ticket=456 {get ticket todos}

GET /todos?project=555 {get project todos}

Input Todo

POST /todos

{
    "title": "example",
    "text": "example",
    "list_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "assigned_id": 458,
    "estimated_remain": 4.8,
    "due_date": "2015-03-31",
    "notify": true,
    "add_alt_tech": true
}

Update Todo

POST /todos

{
    "task_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "title": "example",
    "text": "example",
    "assigned_id": 458,
    "estimated_remain": 4.8,
    "due_date": "2015-03-31",
    "notify": true,
    "time_hours": 4.5,
    "time_no_invoice": false,
    "time_service_id": 4,
    "time_non_working_hours": 2,
    "time_is_taxable": true,
    "time_contract_id": 4,
    "add_alt_tech": true
}

Delete Todo

DELETE /todos/{id} {delete todo}

Complete / UnComplete Todo

PUT /todos/{id}

{
    "is_completed": true
}

Input Todo List a Ticket

POST /todos/list

{
    "ticket_key": "h8s2f2",
    "name": "example",
    "template_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B"
}

Input Todo List to Project

POST /todos/list

{
    "project_id": 458,
    "name": "example",
    "template_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B"
}

Update Todo List

POST /todos/list

{
    "list_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "name": "example"
}

Delete Todo List

DELETE /todos/list/{id} {delete todo list}

Input Todo Template Task

POST /todos/templates/task

{
    "title": "example",
    "text": "example",
    "list_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "assigned_id": 458,
    "estimated_remain": 4.8
}

Update Todo Template Task

POST /todos/templates/task

{
    "task_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "title": "example",
    "text": "example",
    "assigned_id": 458,
    "estimated_remain": 4.8
}

Delete Todo Template Task

DELETE /todos/templates/task/{id} {delete todo template task}

Input Todo Template List

POST /todos/templates/list

{
    "name": "example"
}

Update Todo Template List

POST /todos/templates/list

{
    "list_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "name": "example"
}

Delete Todo Template List

DELETE /todos/templates/list/{id} {delete todo template list}

Files

Get a List of Files

GET /files/ticket=5fg67g {return ticket files list}

GET /files/asset=1001 {return asset files list}

GET /files/{ticket_key} (deprecated, but still supported, will be removed next update)

Get a File

GET /files/{file_id}  {return files itself}

parameter: is_link_only - return only info about file

Post file

POST /files

{
    "asset" : 123, -- (arbitrary) asset id where files will be added
    "ticket" : "ddg3jk", -- (arbitrary) ticket id where files will be added
    "post_id" : "123" -- (arbitrary) post id (from ticket post list) where files will be added (can be any post including initial post)
}    

NOTE:

You can use most common and reliable multipart/form-data on posting files

SAMPLE PAGE

<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<form action="https://api.sherpadesk.com/files" method="POST" enctype="multipart/form-data">
<label><b>Upload Image</b></label>
<div><input type="file" name="img" id="img" /> 
<input name="ticket" value="m4hqne" />
<input name="account"/>
<input name="post_id"/>
<input name="is_tech_only"/>
<button type="submit">Upload</button></div>
</form>
</html>

Delete File

DELETE /files/{file_id}  {delete file}

{
    "asset" : 123, -- (arbitrary) asset id where files will be deleted
    "ticket" : "ddg3jk", -- (arbitrary) ticket id where files will be deleted
}

Users

Get a List of Users

GET /users       {return users list}

GET /users?firstname=Jon&lastname=Vickers&email=jon.vickers@micajah.com  {returns user with Firstname=Jon and Lastname=Vickers and Email=jon.vickers@micajah.com }

GET /users?search=Jon  {returns user with any Firstname=*Jon* or Lastname=*Jon* or Email=*jon* }

GET /users?id=1225  {return user with ID=1225}

filter parameters:

  • role - user role ("admin", "contractor", "tech", "user","superuser", "queue", "notuser", "notuserorcontractor")

  • search - returns user with any Firstname=Jon or Lastname=Jon or Email=jon

  • lastname

  • firstname

  • email

  • account (int) - user account

  • location (int) - user location

  • is_active (bool) - active(true) or inactive (false)

Add new (invite) User

POST /users   

parameters:

  • lastname

  • firstname

  • email

  • account (int) - usually current ticket account

  • location (int) - default location, mandatory if location tracking enabled

  • password (string)

  • password_confirm (string)

  • role (string) - "user" or "tech"

  • is_active (bool) - "true" - for active users, "false" - to inactivate user

all parameters mandatory.

Update existing User (only for ADMINS!)

PUT /users   

{
    "id" : "20", // id of user to update
    "email" : "mymail@com", // email of user to update
    "account" : 111, // integer, move user to Account with id=111 
    "location" : 11, // integer, set Primary Location with id=11, set 0 to clear Primary location
}

Activate/Inactivate existing User (only for ADMINS! You cannot inactivate Techs, only users)

PUT /users   

{
    "id" : "20", // id of user to update
    "is_active" : true, // true to Activate / false - Inactivate user
}

Get a List of Technicians (with CheckIn/Out status)

GET /technicians  {return technicians list}

GET /technicians?firstname=Jon&lastname=Vickers&email=jon.vickers@micajah.com  {returns technician with Firstname=Jon and Lastname=Vickers and Email=jon.vickers@micajah.com }

GET /technicians?search=Jon  {returns technicians with any Firstname=*Jon* or Lastname=*Jon* or Email=*jon* }

GET /technicians?id=1225  {return technicians with ID=1225}

GET /technicians?is_with_statistics {return technicians with statistics of open/closed/onhold tickets}

Projects

Get Projects

GET /projects

GET /projects?account=123 -  get projects of account 123

GET /projects?tech=123 - get tech 123 projects

GET /projects?is_with_statistics=true - get projects with working hours

GET /projects?active_status=-1 - get projects with status (1 - active, 0 - deleted, -1 - archived)

Locations

Get Locations

GET /locations

GET /locations?account=123 -  get Locations of account 123

GET /locations?parent_id=1024 - get child Locations for Location with id=1024

GET /locations?name=Atlanta - get Locations with name Atlanta

GET /locations?is_active=false - get inactive Locations

GET /locations?search=Office - search Locations by name

GET /locations?is_tree=true - get Locations with all Sub-Locations tree

Get Bulk Locations

GET /locations?is_plain=true - get Locations for Account with all Sub-Locations

Note: Please use paging (page and limit)

Get a Location

GET /locations/{location_id}

Add new Location

POST /locations

{
    "name": "Office", // string (max 255 chars), set name
    "description": "my desc", // string (max 255 chars), set desc
    "type_id": 11, // integer, set Location type with id=11 
    "is_active": true, // boolean, set as active(true) or inactive(false)
    "parent_location_id": 12, // integer, set root Location with id=12
    "auditor_id": 2, // integer, set auditor user with id=2 
    "audit_days": 6 // integer, set audit days
}

Update existing Location

PUT /locations/{location_id}

{
    "location_id": 111, // integer, update Location with id=111 
    "name": "Office", // string (max 255 chars), set name
    "description": "my desc", // string (max 255 chars), set desc
    "type_id": 11, // integer, set Location type with id=11 
    "is_active": true, // boolean, set as active(true) or inactive(false)
    "parent_location_id": 12, // integer, set root Location with id=12
    "auditor_id": 2, // integer, set auditor user with id=2 
    "audit_days": 6 // integer, set audit days
}

Add new Location Audit

POST /location/audit

{
    "is_completed": true, // boolean, set as completed(true) or not completed(false)
    "location_id": 12, // integer, set for Location with id=12
    "user_id": 2, // integer, set user with id=2 
    "audit_id": 6 // integer, set audit id to set completed
}

Get a Location Types

GET /location_types

Invoices

Get Invoices

GET /invoices

GET /invoices?account=123 - get invoices of account_id =  123 

GET /invoices?contract_id=123 - get invoices of contract_id =  123

GET /invoices?start_date=2013-10-07&end_date=2013-11-07 - get invoices with date range from 2013-10-07 to 2013-11-07 (by default 30 days ago)

Get an Invoice

GET /invoices/{id} where {id} can be a number(3) or key (t6i0p3)

Get an Unbilled Projects and Tickets

GET /invoices?status=unbilled

Create new invoice

POST /invoices?status=unbilled&contract_id=123&account=6&start_date=2013-10-07&end_date=2013-11-07

!Important: start_date and end_date can be correctly seen from list of call GET /invoices?status=unbilled

Invoice adjustments

You allowed to add or exclude timelogs, and other expenses from invoice.

Add recipients

POST /invoices?status=unbilled&project=0&account=6&recipients=tom@me.com,larry@tt.net 

Review and exclude timelogs and other from invoice

GET /invoices/unbilled?project=0&account=-1&time_logs=1081,1053&products=94bf0d06-547c-4024-bffb-5ec49051c925

Available parameters to exclude:

  • products
  • time_logs
  • adjustments_note
  • adjustments
  • retainers
  • travel_logs

Commit excluded timelogs and other to invoice

POST/invoices/unbilled?project=0&account=-1&time_logs=1081,1053&products=94bf0d06-547c-4024-bffb-5ec49051c925

Send an Invoice to a customer.

PUT /invoices/h263f2   
{ 
   "action" : "sendEmail"
   "recipients" : "tom@me.com,larry@tt.net" 
}

Activate an Invoice.

PUT /invoices/h263f2   
{ 
   "action" : "active"
}

Archive an Invoice.

PUT /invoices/h263f2   
{ 
   "action" : "archive"
}

Mark As Paid an Invoice.

PUT /invoices/h263f2   
{ 
   "action" : "mark as paid"
}

Mark As UnPaid an Invoice.

PUT /invoices/h263f2   
{ 
   "action" : "mark as unpaid"
}

Delete Invoice

DELETE /invoices/{key}

Services

Get Services

GET /services - get all services

GET /services?project=123 - get project 123 services

GET /services?ticket=456  - get ticket services

GET /services?account=123  - get account services

GET /services?tech=456  - get technician services

GET /services?contract=123 - get contract 123 services

Get single Service

GET /services/{key}  

Activity

Get activity of department

GET /activity

Get activity of user

GET /activity?user=33

GET /activity/{user_id} (deprecated, but still supported, will be removed next update)

Time

Additional parameters:

start_date - filters time logs begin from start_date

end_date - filters time logs end from end_date

Get Time Logs of Ticket

GET /time?ticket=gfher5

Get Time Logs of Project

GET /time?project=123

Get Time Logs of Project Tickets

GET /time?project=123&type=tickets

Get Recent Time Logs

type:
* recent - {returns all recent time logs}
* unlinked_fb - {returns all recent unlinked FreshBooks time logs}
* linked_fb - {returns all recent linked FreshBooks time logs}
* invoiced - {returns all recent invoiced time Logs}
* not_invoiced - {returns all recent not invoiced time Logs}
* unlinked_qb - {returns all recent unlinked QuickBooks time logs}
* linked_qb - {returns all recent linked QuickBooks time logs}
* hidden_from_invoice - {returns all recent hidden from invoice time logs}
* do_no_invoice - {returns all recent marked as "No Invoice" time logs}

project - {project id}

account - {account id}

tech - {technician id}

i.e.
GET /time?type=recent&project=123&account=354&tech=465

Get single Time Log Entry

GET /time?ticket_time_id=23 {return a ticket time log record}
GET /time?project_time_id=678 {return a project time log record}

GET /time/123?type=ticket (deprecated, but still supported, will be removed next update)

GET /time/123?type=project (deprecated, but still supported, will be removed next update)

Input Time a Ticket

POST /time

{
    "ticket_key": "h8s2f2",
    "note_text": "example",
    "service_id": 2,
    "hours": 2,
    "date": "2014-03-31",
    "start_date": "2014-03-31 11:14:20:00",
    "stop_date": "2014-03-31 13:14:20:00",
    "tech_id": 27,
    "no_invoice": false,
    "complete" : "20", //percent
    "remain_hours": 3,
    "prepaid_pack_id": 4,
    "non_working_hours": 2,
    "contract_id": 4,
    "is_taxable": true,
    "is_local_time" true, // handle start_date and stop_date as local time
    "note_internal": "example",
    "event_id": "c8801133-a6aa-4419-a2ba-1c2fe2c9ce71"
}

Input Time to Project or Account

POST /time

{
    "tech_id" : 543,
    "project_id": "3421",
    "account_id" :"-1",
    "note_text": "example",
    "service_id": 2,
    "hours": 2.5,
    "date": "2014-03-31",
    "start_date": "2014-03-31 11:14:20:00",
    "stop_date": "2014-03-31 13:14:20:00",
    "complete" : "20", //percent
    "remain_hours": 3,
    "prepaid_pack_id": 4,
    "no_invoice": false,
    "non_working_hours": 2,
    "contract_id": 4,
    "is_taxable": true,
    "is_local_time" true, // handle start_date and stop_date as local time
    "note_internal": "example"
}

Update Time a Ticket

PUT /time/{key}

{
    "note_text": "example",
    "service_id": 2,
    "hours": 2,
    "date": "2014-03-31",
    "start_date": "2014-03-31 11:14:20:00",
    "stop_date": "2014-03-31 13:14:20:00",
    "tech_id": 27,
    "complete" : "20", //percent
    "remain_hours": 3,
    "prepaid_pack_id": 4,
    "no_invoice": false,
    "non_working_hours": 2,
    "contract_id": 4,
    "is_taxable": true,
    "is_local_time" true, // handle start_date and stop_date as local time
    "note_internal": "example"
}

Update Time to Project or Account

PUT /time/{key}

{
    "is_project_log": true,
    "tech_id" : 543,
    "project_id": "3421",
    "account_id" :"-1",
    "note_text": "example",
    "service_id": 2,
    "hours": 2.5,
    "date": "2014-03-31",
    "start_date": "2014-03-31 11:14:20:00",
    "stop_date": "2014-03-31 13:14:20:00",
    "prepaid_pack_id": 4,
    "no_invoice": false,
    "non_working_hours": 2,
    "contract_id": 4,
    "is_taxable": true,
    "is_local_time" true, // handle start_date and stop_date as local time
    "note_internal": "example"
}

POST /project_time (removed)

Time Entry as No Invoice

PUT /time/{key}

{
"no_invoice" : true
}

Hide / Unhide Time Entry from Invoice

PUT /time/{key}

{
"hidden_from_invoice" : true
}

Delete Time

DELETE /time/{key}

Travel Logs

Add Travel Log to ticket

POST /travel_logs

{
    "ticket_key": "h8s2f2",
    "start_location": "New York",
    "end_location": "Moscow",
    "distance": 2000,
    "rate": "2.5",
    "date": "2014-03-31",
    "note": "my travel",
    "is_technician_payment": true,
    "contract_id": 4
}

Add Travel Log to Account

POST /travel_logs

{
    "account": "111",
    "start_location": "New York",
    "end_location": "Moscow",
    "distance": 2000,
    "rate": "2.5",
    "date": "2014-03-31",
    "note": "my travel",
    "is_technician_payment": true,
    "contract_id": 4
}

Hide / Unhide Travel Log from Invoice

PUT /travel_logs/{key}

{
"hidden_from_invoice" : true
}

Delete Travel Log

DELETE /travel_logs/123

Assets

Get Assets

GET /assets

{
    "search": "", // string (max 255 chars), search assets by any field
    "filter": "my", // string (max 255 chars), use "my" to show only my owned assets
    "user_id": 11, // integer, show assets checked out by user with id=11 
    "owner_id": 12, // integer, show assets owned by user with id=12
    "account_id": 1, // integer, show assets in account with id=1
    "location_id": 2, // integer, show assets in location with id=2 and all child locations
    "is_active": true // boolean, show only active (true) or inactive (false) or all (undefined) assets
    "status": 6 // integer, show only assets with status id=6,
    "category_id": 111, // integer, show assets with category_id=111 
    "type_id": 112, // integer
    "make_id": 113, // integer
    "model_id": 114, // integer,
    "is_with_custom_fields": false// boolean, show custom_fields (true) or no (false) or all assets 
}

Search Assets by Tag or Unique field

GET /assets/search

{
    "test": "102345", // string (max 255 chars), search assets by any Unique field
    "account_id": "0", // integer, show assets in account with id=0
}

Get Asset Categories

GET /asset_categories

Get Asset Types

GET /asset_types

{
   "category_id: 111, // integer 
}

Get Asset Makes

GET /asset_makes

{
    "type_id: 112, // integer      
}

Get Asset Models

GET /asset_models

{
    "make_id: 113, // integer      
}

Get Asset Statuses

GET /asset_statuses

{
  "is_active": true // boolean, show only active (true) or inactive (false) or all (undefined) statuses
}

Get Asset Custom Fields

GET /customfields

{
  "asset_type_id": 3, // integer, show Custom Fields for this type
  "asset_id": 345, // integer, optional, show Custom field Values for Asset
}

Add new Custom Field

POST /customfields

{
  "caption": "My field", 
  "type": 1, //integer, create Custom Fields for this type
}

Note: Type is one of following:

    1        single line

    2        multi line

    3        single answer

    6        multi answer

    4        multi answers

    5        Date Time

Edit Custom Field

PUT /customfields/123

{
  "caption": "new caption",
}

Add Asset

NOTE: please use checkout_id to update as ANOTHER user - this user will be stored in log

NOTE 2: You can attach existing Assets during ticket creation, see Create Ticket section

POST /assets

{
    "checkout_id" : 2 //integer see get Users section to get Id. Please skip value or set 0 to not set checkout_id.
    "is_bulk": false, // boolean
    "is_force_dublicate": false, // boolean
    "serial_number": "11", // string (max 50 chars),
    "category_id": 111, // integer 
    "type_id": 112, // integer
    "make_id": 113, // integer
    "model_id": 114, // integer
    "unique1_value": "u111", // string (max 100 chars),
    "unique2_value": "u112", // string (max 100 chars),
    "unique3_value": "u113", // string (max 100 chars),
    "unique4_value": "u114", // string (max 100 chars),
    "unique5_value": "u115", // string (max 100 chars),
    "unique6_value": "u116", // string (max 100 chars),
    "unique7_value": "u117", // string (max 100 chars),
    "unique_motherboard": "m11", // string (max 100 chars),
    "unique_bios": "b11", // string (max 100 chars),
    "name": "name11", // string (max 50 chars),
    "description": "d11", // string (max 250 chars),
    "location_id": 0 // integer,
    "account_id": 0 // integer,
    "status_id": 3 // integer,
    "entered_date", // date string in ISO format ("2017-06-14T18:42:36.9330000"),
    "note", // string (max 250 chars)
}

Update Asset

NOTE: please use checkout_id to update as ANOTHER user - this user will be stored in log

PUT /assets/{id} // id integer, is asset id to change

{
    "is_bulk: false, // boolean
    "is_active: true, // boolean
    "is_force_dublicate: true, // boolean
    "checkout_id: 1, // integer
    "owner_id: 12, // integer
    "account_id: 13, // integer
    "serial_number: "11", // string (max 50 chars),
    "category_id: 111, // integer 
    "type_id: 112, // integer
    "make_id: 113, // integer
    "model_id: 114, // integer
    "unique1_value: "u111", // string (max 100 chars),
    "unique2_value: "u112", // string (max 100 chars),
    "unique3_value: "u113", // string (max 100 chars),
    "unique4_value: "u114", // string (max 100 chars),
    "unique5_value: "u115", // string (max 100 chars),
    "unique6_value: "u116", // string (max 100 chars),
    "unique7_value: "u117", // string (max 100 chars),
    "unique_motherboard: "m11", // string (max 100 chars),
    "unique_bios: "b11", // string (max 100 chars),
    "name: "name11", // string (max 50 chars),
    "description: "d11", // string (max 250 chars),
    "note: "my note", // string (max 500 chars),
    "location_id: 0 // integer,
    "status_id": 6 // integer, show only assets with status id=6
    "entered_date": "2017-06-20T13:12:01.3600000" //string, Represent date in iso format 
    "acquired_date": "2017-06-20T13:12:01.3600000" //string, Represent date in iso format 
    "po_number: "2345 n/a", // string,
    "paid_value: "4.80", // string,
    "funding_source: "test", // string 
}

More info Doc

Bulk operations on Add and Update Assets

Note: Max Limit for one Bulk operation is 100 commands

Now available adding new assets (POST) and updating assets (PUT).

Bulk list contains list of update requests as list of URLs.

POST /assets/bulk?format=json

{
    "bulk"	: [
	"assets?note=My new note",
	"assets?owner_id=909666",
    "assets?checkout_id=1032264", 
	"assets?status_id=1&location_id=171897&unique1_value=10028",
	"assets?checkout_id=0"
    ]

}

PUT /assets/bulk?format=json

{
    "bulk"	: [
	"assets/826717?note=My new note",
	"assets/826717?owner_id=909666",
    "assets/826717?checkout_id=1032264", 
	"assets/826717?status_id=1&location_id=171897&unique1_value=10028",
	"assets/826717?checkout_id=0"
    ]

}

Examples:

"assets/826717?note=My new note" - Will update asset with id 826717 with new NOTE "My new note"

"assets/826717?status_id=1&location_id=171897&unique1_value=10028" - Will update asset with id 826717 with new Status_id = 1, new Location_id = 171897, and new Unique1_value = 10028

Products

Get Recent Products

GET /products?type=recent&project=123&account=354&tech=465

type:
* recent - {returns all recent products}
* unlinked_fb - {returns all recent unlinked FreshBooks products}
* unlinked_fb_billable - {returns all recent unlinked FreshBooks and Billable products}
* linked_fb - {returns all recent linked FreshBooks products}
* invoiced - {returns all recent invoiced products}
* not_invoiced - {returns all recent not invoiced products}
* not_invoiced_billable - {returns all recent not invoiced and Billable products}
* not_invoiced_nonbillable - {returns all recent not invoiced and Non Billable products}
* unlinked_qb - {returns all recent unlinked QuickBooks products}
* unlinked_qb_billable - {returns all recent unlinked QuickBooks and Billable products}
* linked_qb - {returns all recent linked QuickBooks products}
* hidden_from_invoice - {returns all recent hidden from invoice products}

project - {project id}

account - {account id}

tech - {technician id}

with_travel - optional (true or false)

i.e.
GET /products?type=recent&project=123&account=354&tech=465&with_travel=true

Get single Product

GET /products/{key}  

Product as Billable / Non Billable

PUT /products/{key}

{
"is_billable" : true
}

Hide / Unhide Product from Invoice

PUT /products/{key}

{
"hidden_from_invoice" : true
}

Get single Product Item

GET /products/product_items/{key} 

Delete single Product Item

DELETE /products/product_items/{key} 

Activate/Deactivate single Product Item

PUT /products/product_items/{key}

{
"is_active" : true
}

Input Product a Ticket

POST /products

{
    "ticket_key": "h8s2f2",
    "tech_id": 27,
    "note": "example",
    "note_internal": "example",
    "amount": 2,
    "is_billable": true,
    "product_item_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "vendor": "vendor name",
    "markup": 10, // %
    "markup_value": 5.2, // money
    "date": "2014-03-31",
    "is_technician_payment": true,
    "units": 2,
    "contract_id": 24,
    "is_taxable": true
}

Input Product to Project or Account

POST /products

{
    "account_id": 125,
    "project_id": 458,
    "tech_id": 27,
    "note": "example",
    "note_internal": "example",
    "amount": 2,
    "is_billable": true,
    "product_item_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "vendor": "vendor name",
    "markup": 10, // %
    "markup_value": 5.2, // money
    "date": "2014-03-31",
    "is_technician_payment": true,
    "units": 2,
    "is_taxable": true
}

Update Product a Ticket

POST /products

{
    "product_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "ticket_key": "h8s2f2",
    "tech_id": 27,
    "note": "example",
    "note_internal": "example",
    "amount": 2,
    "is_billable": true,
    "product_item_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "vendor": "vendor name",
    "markup": 10, // %
    "markup_value": 5.2, // money
    "date": "2014-03-31",
    "is_technician_payment": true,
    "units": 2,
    "is_taxable": true
}

Update Product to Project or Account

POST /products

{
    "product_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "account_id": 125,
    "project_id": 458,
    "tech_id": 27,
    "note": "example",
    "note_internal": "example",
    "amount": 2,
    "is_billable": true,
    "product_item_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B",
    "vendor": "vendor name",
    "markup": 10, // %
    "markup_value": 5.2, // money
    "date": "2014-03-31",
    "is_technician_payment": true,
    "units": 2,
    "is_taxable": true
}

Delete Product

DELETE /products/{key}

Payments

Get an Payment

GET /payments/{id} where {id} can be a number(3)

PrePaid Packs

Get PrePaid Packs

GET /prepaid_packs
{
    "contract_id": 123, // optional get for contract with id=123 (default is local account)
    "date": "2014-03-31"
}

Get an PrePaid Pack

GET /prepaid_packs/{prepaid_pack_id}

Contracts

Get Contracts

GET /contracts
{
    "account_id": 123, // optional get for account with id=123 (default is local account)
    "date": "2014-03-31",
    "for_time_logs": true // optional. If true, then get contracts allowed for Time Logs, otherwise get all contracts (default value: true) 
}

Get an Contract

GET /contracts/{contract_id}

Get an Contract Product

GET /contracts/products/{contract_product_id}

FreshBooks

Get FreshBooks Clients

GET /freshbooks/clients

Create FreshBooks Client from SherpaDesk Account

POST /freshbooks/clients

{
    "account_id": 123
}

Unlink FreshBooks Client

DELETE /freshbooks/clients/{key}

{
    "is_unlink": true
}

Delete FreshBooks Client

DELETE /freshbooks/clients/{key}

Get FreshBooks Staff

GET /freshbooks/staff

Unlink FreshBooks Staff

DELETE /freshbooks/staff/{key}

Get FreshBooks Projects

GET /freshbooks/projects/?client=123&staff=321&identity=213

Create FreshBooks Project from SherpaDesk Project

POST /freshbooks/projects

{
    "project_id": 123,
    "fb_client_id": 12,
    "fb_staff_id": 2,
    "account_id": 123,
    "fb_identity_id": 3
}

Unlink FreshBooks Project

DELETE /freshbooks/projects/{key}

{
    "is_unlink": true
}

Delete FreshBooks Project

DELETE /freshbooks/projects/{key}

Get FreshBooks Tasks

GET /freshbooks/tasks/?project=123

Create FreshBooks Task from SherpaDesk Service

POST /freshbooks/tasks

{
    "service_id": 123,
    "fb_project_id": 12
}

Find FreshBooks Task

GET /freshbooks/tasks?name=general

Unlink FreshBooks Task

DELETE /freshbooks/tasks/{key}

{
    "is_unlink": true
}

Delete FreshBooks Task

DELETE /freshbooks/tasks/{key}

Input FreshBooks Time Entry

POST /freshbooks/time

{
    "fb_staff_id": 123,
    "fb_project_id": 321,
    "fb_task_type_id": 2,
    "hours": 2,
    "notes": "example",
    "date": "2014-03-31",
    "time_id": 123,
    "non_working_hours": 2,
    "fb_client_id": 321
}

Update FreshBooks Time Entry

PUT /freshbooks/time/{key}

{
    "fb_staff_id": 123,
    "fb_project_id": 321,
    "fb_task_type_id": 2,
    "hours": 2,
    "notes": "example",
    "date": "2014-03-31",
    "non_working_hours": 2,
    "fb_client_id": 321
}

Unlink FreshBooks Time Entry

DELETE /freshbooks/time{key}

{
    "is_unlink": true
}

Delete FreshBooks Time Entry

DELETE /freshbooks/time/{key}

Input FreshBooks Expense

POST /freshbooks/expense

{
    "fb_staff_id": 123,
    "fb_category_id": 2,
    "fb_project_id": 321,
    "fb_client_id": 2,
    "amount": 2,
    "vendor": "vendor name",
    "notes": "example",
    "date": "2014-03-31",
    "product_id": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B"
}

Update FreshBooks Expense

PUT /freshbooks/expense/{key}

{
    "fb_staff_id": 123,
    "fb_category_id": 2,
    "fb_project_id": 321,
    "fb_client_id": 2,
    "amount": 2,
    "vendor": "vendor name",
    "notes": "example",
    "date": "2014-03-31"
}

Unlink FreshBooks Expense

DELETE /freshbooks/expense/del/{key}

{
    "is_unlink": true
}

Delete FreshBooks Expense

DELETE /freshbooks/expense/del/{key}

Get FreshBooks Categories

GET /freshbooks/category/

Input FreshBooks Category

POST /freshbooks/category

{
    "category_id ": "0AC642DE-468A-4B7A-8DB8-0FF3E4353E1B"
}

Unlink FreshBooks Category

DELETE /freshbooks/category/del/{key}

{
    "is_unlink": true
}

Delete FreshBooks Category

DELETE /freshbooks/category/del/{key}

Link FreshBooks Stuff

POST /freshbooks

{
    "user_id": 123,
    "fb_staff_id": 321,
    "account_id": 25,
    "fb_client_id": 12,
    "project_id": 123,
    "fb_project_id": 3,
    "service_id": 2,
    "fb_task_type_id": 4,
    "product_item_id": "17206C73-DC07-46BE-8FA9-42A0E4CDC11A",
    "fb_category_id": 2,
    "tax_rate_id": 3,
    "fb_tax_id": 4,
    "fb_identity_id": 5
}

Custom Fields

Get Ticket Custom Fields

GET /customfields

{
  "class_id": 3 // integer, show Custom Fields for this class
}

Get one Custom Field

GET /customfields

{
  "custom_id": 345, // integer, show Custom field
}

Get Asset Custom Fields

GET /customfields

{
  "asset_type_id": 3, // integer, show Custom Fields for this type
  "asset_id": 345, // integer, optional, show Custom field Values for Asset
}

Update Ticket Custom Fields

POST /customfields

{
    "ticket_key": "ert34f",
    "custom_xml": "<root><field id="1"><caption>Have You Rebooted?</caption><value>Yes</value></field></root>",
}

Tax Rates

Get an Tax Rate

GET /tax_rates/{tax_rate_id}

Events

Get Events

GET /events
{
    "account": 123, // optional. account id
    "tech": 123, // optional. technician id
    "date": "2014-03-31"
}

Get an Event

GET /events/{event_id}

Links

RESTful API Server – Doing it the right way (Part 1) (http://blog.mugunthkumar.com/articles/restful-api-server-doing-it-the-right-way-part-1/) Nobody Understands REST or HTTP (http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http)

Clone this wiki locally