Forums/Documentation/Developers

C# wrapper for the Zendesk REST API

Eric Neifert
posted this on February 08, 2011 10:00

Here's a full C# wrapper for the Zendesk REST API: https://github.com/eneifert/ZendeskApi_v2. The readme contains a list of all the public methods, but hopefully it will be simple to use. The code is of course open source, so feel free to add or make whatever changes you like.

If you aren't familiar with GitHub, visit their help page.

Enjoy and feel free to ask questions.

 

Comments

User photo
Jake Holman
Product Manager

Nice work, Eric!

February 08, 2011 10:14
User photo
David Finch
oddslifehelp

Hey Eric,

 

I was just in the process of writing one of these when I came to this forum to ask a question.  Seems however that there is already something available for what I am trying to create (your API wrapper).  However, my question still remains;

 

I notice in your readme.txt where you detail all your public methods there exists two methods as follows;

bool UpdateTicket(int ticketId, string description);

bool UpdateTicket(int ticketId, Comment comment);

 

Am I correct in thinking then that you cannot update a ticket with (for example) changed values of custom fields, altered subject title ect ?

February 11, 2011 00:17
User photo
Eric Neifert
csharpapi

Hi David,

Thanks for helping to make this api better. I have just added a method to do what you are asking about. bool UpdateTicket(Ticket ticket)

Here is how you update custom fields:

var myTicketFields = api.GetTicketFields();

var myTicket = api.GetTicketById(yourTicketId);
myTicket.TicketFieldEntries.Add(new TicketFieldEntry
                                                {
                                                    TicketFieldId = myTicketFields.Find(x => x.Title == "some title").Id,
                                                    Value = "my new value"
                                                });
api.UpdateTicket(myTicket);

Hope this helps,

Eric

 

February 11, 2011 06:09
User photo
David Finch
oddslifehelp

Wow Eric, speedy update, thank you !

I have not had chance to try it out yet but will do over the weekend and get back to you.  We have a drop down field which our external program controls the selected item.  We have the field-id for it but could not see a way with your previous documentation how this could be maintained.

 

Now all I must do is figure out this Git Hub thing and I'm away.

 

Regards,

David

February 11, 2011 11:07
User photo
David Finch
oddslifehelp

Eric,

Im having issues getting your tests to pass.  Specifically the "CanGetATicket".  I have filled out my specific details in ZenDeskSettings and have created a test ticket which most certainly does have comments attached to it, both public and private made by both agents and requester.  I have then placed the nice-id of this ticket into the '_api.GetTicketById()' method.  However the test is failing on the Assertion that the comments are greater than 0 because the Comments object itself is null.

 

Any ideas why this may be ?

 

Regards,

David

February 17, 2011 07:08
User photo
Eric Neifert
csharpapi

Hmm, I checked them all again today and the tests should all pass if you have the settings correct. Can you tell me if anyone them pass?

February 17, 2011 13:18
User photo
David Finch
oddslifehelp

It is strange.  Sometimes the 'CanGetForums' will pass but not anymore. More often than not it will ask me to find the source of View.cs.  Now however, it seems to be consistently failing all tests.

 

Please find attached the xml output from running NUnit.

February 17, 2011 23:25
User photo
David Finch
oddslifehelp

Hi Eric,

From playing around with it further, there is something in your code which believes the location of your model classes are still on your machine.  I was debugging your tests and tried to step-into the api.GetTicketById() method.  It then said that it could not find 'Ticket.cs' in the location 'C:\Users\<your username>\Documents\Visual Studio 2010\Projects\'. I pointed the debugger at the correct location for Ticket.cs relative to my machine but still, after each build, it keeps trying to look for that location on your machine.

Any ideas what's going on?

February 20, 2011 03:23
User photo
David Finch
oddslifehelp

I have now re-downloaded your solution.  Cleaned it, compiled it and re-tested. It can now find the location of Ticket.cs but I get the same error as previously mentioned but searching for 'RestClient.Sync.cs', again, it is looking for it in a location on your machine.

February 20, 2011 03:33
User photo
David Finch
oddslifehelp

Ok, sorry for the hassle but I really want to get to the bottom of this.  I have managed to get all the code talking to each-other correctly, i.e not looking for locations of source on your machine.

The code is failing to return a Ticket object with any values.  It fails on ZendeskApi.Execute<T>(ZenRestRequest request).  If I use the debugger to inspect the response variable produced by _client.Execute<T>(request); I see that it has an errorExeption as follows;

 

 

System.ArgumentException: Can not convert Integer to String.
   at Newtonsoft.Json.Linq.JToken.op_Explicit(JToken value)
   at RestSharp.Extensions.MiscExtensions.AsString(JToken token)
   at RestSharp.Deserializers.JsonDeserializer.Map(Object x, JToken json)
   at RestSharp.Deserializers.JsonDeserializer.CreateAndMap(Type type, JToken element)
   at RestSharp.Deserializers.JsonDeserializer.BuildList(Type type, JEnumerable`1 elements)
   at RestSharp.Deserializers.JsonDeserializer.Deserialize[T](RestResponse response)
   at RestSharp.RestClient.Deserialize[T](RestRequest request, RestResponse raw)

System.ArgumentException: Can not convert Integer to String.   at Newtonsoft.Json.Linq.JToken.op_Explicit(JToken value)   at RestSharp.Extensions.MiscExtensions.AsString(JToken token)   at RestSharp.Deserializers.JsonDeserializer.Map(Object x, JToken json)   at RestSharp.Deserializers.JsonDeserializer.CreateAndMap(Type type, JToken element)   at RestSharp.Deserializers.JsonDeserializer.BuildList(Type type, JEnumerable`1 elements)   at RestSharp.Deserializers.JsonDeserializer.Deserialize[T](RestResponse response)   at RestSharp.RestClient.Deserialize[T](RestRequest request, RestResponse raw)

 

Does this seem strange to you ?  Your code appears to be set up to request and recieve xml, however the request and response objects are using json to transfer data.  Could this be the reason for null references and such exceptions as detailed above?  An XMLSerializer attempting to parse json ?

 

February 20, 2011 04:05
User photo
Eric Neifert
csharpapi

Hi David,

It is no hassle and I thank you for looking into this. One thing I noticed is that my tests pass when I have the settings pointed to the trial version account where as some fail when I have them pointed to our new production account. The overall problem lies in the Deserialization of the xml (going from the xml to the objects). I have posted an issue on the RestSharp google group and got a reply back yesterday. I am going to look over his response more tomorrow morning. I will let you know what I find.

And as per your last comment, I knew before that their was some funkyness in the xml parsing before but tried to get around it by using json where possible. I see now that was a mistake and will go back and change that to always use xml. Also if the content-type is json then the application would not try to serialize it using json, it would use the RestSharp JsonSerializers.

Take care,

Eric

February 20, 2011 06:11
User photo
Eric Neifert
csharpapi

Hi David,

I re-wrote how all the xml deserialization happens. If you get the latest code now, I think all of your tests should pass. Let me know if any do not.

Have a good day,

Eric

February 21, 2011 06:55
User photo
David Finch
oddslifehelp

Hi Eric,

Yes ! Thank you this works perfectly now.  Thought I spotted an issue with .GetTicketsInView as none of the ticket object had .TicketFieldEntries values but then I realise the xml returned for this query doesnt include field info anyway so there is no way you could populate these properties. 

Thank you very much for your help with this code, you have saved me masses of development time.

 

Regards,

David.

February 22, 2011 02:27
User photo
David Finch
oddslifehelp

Eric,

I could not see a test for adding different types of comments to an existing ticket.  Can you confirm that your API is able to add both public and private comments to a ticket ?  Its just all comments submitted, regardless of the Comment objects "isPublic" property value seem to come out as private.

February 22, 2011 12:16
User photo
Eric Neifert
csharpapi

David,

Thanks again for taking the time to post your questions. Looks like ZenDesk does not accept the value "True" for bools, they only accept lower case "true". I will change the serializer it to use lower case for booleans.

Eric

February 23, 2011 12:40
User photo
David Finch
oddslifehelp

Eric,

No need to thank, your time and effort in building this API in the first place has saved me huge amounts.  To siply use it and report back to you is the least I can do.

When you update your API with the aforementioned change, would it be possible to download only the object you modified.  Its just, I have made a minor change in your ticket object so that I do not get null reference exceptions and also so new comments are automatically added to the ticket upon submission.  Obviously if I update your entire API, these changes will be reverted and ill have to put it back in every time I update.

Regards,

David

February 23, 2011 13:02
User photo
Eric Neifert
csharpapi

David,

I made the changes and verified that public comments now work. Also please put any future questions here: https://github.com/eneifert/ZendDeskApi/issues

Have a good day,

February 23, 2011 13:10
User photo
Eric Neifert
csharpapi

Also the only file that really has changed here is the ZenDeskXmlSerializer, so you can just get that.

February 23, 2011 13:13
User photo
Michael Gold

Hi, I am creating a ticket using the CreateTicketAsEndUser. I am setting

 

t.TicketTypeId = (int)TicketType.Problem;
            t.PriorityId = (int) TicketPriorities.Urgent;

t.TicketTypeId = (int)TicketType.Problem;            

t.PriorityId = (int) TicketPriorities.Urgent;

 

In Zend it is not showing the ticket created with these settings. 

Thanks

April 05, 2011 05:33
User photo
Jeff Smith

I am totally lost with this API wrapper. How are you folks "running the tests"? When I try to run, there is no output class specified. How do I make this stuff run (out-the-box)? What can I do to step through this stuff and see it actually work with my settings?


This looks really cool and useful. I am completely unsure how to begin making it work....any ideas how to run the test project?

April 15, 2011 13:15
User photo
David Finch
oddslifehelp

Hi Jeff,

The test  project is a class library so you wont be able to run it 'out of the box'.  If my memory serves me correctly, the tests are built using NUnit.  If so, you will need to download the NUnit runner *rummage for link* http://www.nunit.org/?p=download Once you have this, open it, select file > open project and select the .Tests .dll.  I cant remember the exact name of the test project but ill assume if your asking about using this your clued up on how to find the output .dll of a project.  Once you have loaded this correctly you will see a list of tests available to you and you can run them from the GUI.

 

If you would like to step over the code yourself and inspect object properties, you will need to attach it to the NUnit process. To do this, from inside visual studios, i THINK its in the debug menu; Debug > Attach to process (might be Ctrl + P for a shortcut) and select the Nunit process from the menu (Not the Nunit agent)  now when you move back to your NUnit runner, and run a test, it will stop on any breakpoints you have set.

 

Hope this helped.

April 17, 2011 04:48
User photo
Mikhail Zakharov
Портал технической поддержки

Hi, Eric.

I'm trying to use the ZenDeskApi Wrapper. My test application using ZenDeskApi.GetOrganizations method to get all organizations. But it's return nothing. I used Fiddler to debug. And there is correct responce with organizations data In a trace log.

I found some strange things in method (Core.cs):
        public T Execute<T>(ZenRestRequest request) where T : new()
        {
            var response = _client.Execute<T>(request);           
            return response.Data;
        }

In quick watch window (see attach) "Data" property is null. But "Content" property contains a value. And there is error message in "Error exception". Would you explain this and help me?

May 19, 2011 04:42
User photo
Eric Neifert
csharpapi

Hi Mikhail,

Seems like the project is missing a reference to Newtonsoft.Json.Net35. This dll was removed completely in Feb so I would recommend just getting the latest version. However, if you are all ready in a production environment and don't want to update then you could download the dll from here: http://json.codeplex.com/releases/view/50552 and add it to your project.

 

(Also for future reference please submit any new issues/questions to here: https://github.com/eneifert/ZendDeskApi/issues)

Hope this helps,

Eric

May 19, 2011 05:02
User photo
Mikhail Zakharov
Портал технической поддержки

Eric,

Thanks for assist. I'll try to work with references to Newtonsoft.Json.Net35. If I find a bug I'll post it to GitHub

May 19, 2011 06:57
User photo
Harpreet Kaur

please send me completeasp.net application integrated with zendesk,

 

or kindly send me links from where i maka asp.net application using zendesk.

because i am very new in this line.

 

i am serching zendesk application in asp.net but cant find that how to make it step wise. kindly help me, its urgent

 

May 19, 2011 23:08
User photo
Mikhail Zakharov
Портал технической поддержки

Hi Eric,

Thanks fo advice. Problem is in wrong reference.

May 20, 2011 01:52
User photo
Eric Neifert
csharpapi

Hello Harpreet,

Your question goes a little beyond the scope of this forum but I will try to give you some direction.  

If you are new to asp.net mvc you best place to go is http://tekpub.com/channels/microsoft Watch his series on mastering asp.net mvc and also try out his examples and you will be an asp.net guru in no time.

If you are working with asp.net web forms, I would strongly recommend switching to mvc if possible (in my humble opinion: this is where the asp.net industry is going and will make you a more valuable developer), but if you are set on web forms I guess you should start out by finding some good tutorials on the web. Here is one I found which might help you: http://webproject.scottgu.com/CSharp/HelloWorld/Helloworld.aspx 

Now on to using the zendesk api. Download all the dlls from here: https://github.com/eneifert/ZendDeskApi/tree/master/Output. Then add them as references in your project.

Now in your code where you want to use the api just instantiate it like this: ZenDeskApi.ZenDeskApi _api = new ZenDeskApi.ZenDeskApi("http://yousite.zendesk.com", "your_admin_email_here",

                                                                   "password here");

As for what you can do from there I would say to check out the readme file at: https://github.com/eneifert/ZendDeskApi or look through the test class at: https://github.com/eneifert/ZendDeskApi/blob/master/ZenDeskTests/ZenDeskTests.cs for more examples of what the api can do.

Best of luck,

Eric 

May 20, 2011 05:43
User photo
Eric Neifert
csharpapi

This project is now on Nuget and should make things easier to install in the future. 

To use in Visual Studio just right click on "References" and select "Add Library Package Reference". Then search for Zendesk in online section, click install and you are good to go!

3 cheers for Nuget!

June 14, 2011 12:29
User photo
Dmitry Kirillov

Hello Eric. Great job.

I tried to use your api in the following way:

User user = api.GetUserById(66705667);
Organization org = api.GetOgranizationById(20131763);
org.Users = new List<User> {user};
api.CreateOrUpdateOrganization(org);

So i need to add an user to an organization. But it does not work. Could you please advice whether it's possible and if it is what I do wrong?

Dima.

June 24, 2011 11:37
User photo
Dmitry Kirillov

I found an issue. Some properties in User class were not serialized because of Skip = true 

June 24, 2011 12:06
User photo
Dylan Clendenin
Zendesk

Out of curiosity, why did you name the library "zendDesk" (note the extra 'd')? Intentional or typo?


June 24, 2011 16:09
User photo
Eric Neifert
csharpapi

@Dmitry. At the time when the api was written, if those extra params were sent (serialized) Zendesk would throw an error. I just tested the GetOrganizationById method and it worked fine for me so I cannot reproduce your problem to help give any further insight. Seems like you got it all worked out though.

@Dylan. Yep that would be a typo. Not sure it is worth changing though seeing as how everyone would have to update their settings if they every tried to get the latest again.

June 27, 2011 05:40
User photo
Dylan Clendenin
Zendesk

I'd say it is worth it because it is the name of a brand, spelling it correctly seems like the right thing to do to me. But I'm not the maintainer and it's your repo, so all I can do is try to persuade. :)

June 27, 2011 10:45
User photo
Matthew Smith

Eric,

Looks like a great library here!  Do you believe this can be brought over for Windows Phone 7?

July 14, 2011 06:09
User photo
Eric Neifert
csharpapi

Thanks Matthew, but I don't know much about windows phone. Anyone else have any thoughts?

July 14, 2011 06:40
User photo
Matthew Smith

Eric,

Thanks for your reply.  I've had a bit of a look at bringing it over and there are a couple of things not available in Siverlight on the phone, such as XmlDocument. XmlNodeList and MD5CryptoServiceProvider.  Might be possible with some changes, but without playing around not entirely sure.

July 14, 2011 21:28
User photo
Matthew Smith

I've had  a bit of a go but cannot get it to return any data via the Execute function (needed to convert to ExecuteAsync).  I'm more into VB than C# so all the callback stuff is bit over the top for me.  Anyway, hopefully we'll see a Zendesk WP7 app soon.

July 15, 2011 08:01
User photo
Eric Neifert
csharpapi

Just wanted to let everyone know the wrapper is now correctly named "ZenDeskApi" and is located here: https://github.com/eneifert/ZenDeskApi

July 15, 2011 09:02
User photo
Antriksh
Hi Eric, I am using .NET 2.0 version on which the code you are provided is not running.Do you have the code which I can run on .NET 2.0.
August 18, 2011 02:52
User photo
Eric Neifert
csharpapi
Sorry Antriksh, the code does not support .NET 2.0 and I am not looking to add this. For the wrapper itself you could create a new project and import the files if you want to use it as kind of a guide, but the problem is that some of the references are 3.5 and 4.0 so you would be out of luck there. If you can upgrade your project to 4.0 I would recommend doing that. 4.0 has many new great features but also will work fine with your older 2.0 code and any referenced assemblies. See this for more information: http://stackoverflow.com/questions/2653566/what-happens-when-net-4-... Best of luck, Eric
August 18, 2011 04:54
User photo
Mikhail Zakharov
Портал технической поддержки
Hi Eric. There is some issues with user management in wrapper. I post it at https://github.com/eneifert/ZenDeskApi/issues/9
August 19, 2011 05:18
User photo
Aram Osipyan

Eric i have found that while retriving Users list your serializer does not get Role values. I have captured Request/Response from your application and can see that in response xml those values are present and not null

<user>
<created-at type="datetime">2011-11-04T16:50:26+03:00</created-at>
<details nil="true"></details>
<external-id nil="true"></external-id>
<id type="integer">113174728</id>
<is-active type="boolean">true</is-active>
<last-login type="datetime" nil="true"></last-login>
<locale-id type="integer" nil="true"></locale-id>
<name>Jennifer Hansen</name>
<notes nil="true"></notes>
<openid-url nil="true"></openid-url>
<organization-id type="integer" nil="true"></organization-id>
<phone nil="true"></phone>
<restriction-id type="integer">4</restriction-id>
<roles type="integer">0</roles>
<time-zone>UTC</time-zone>
<updated-at type="datetime">2011-11-04T16:50:26+03:00</updated-at>
<uses-12-hour-clock type="boolean">true</uses-12-hour-clock>
<current-tags></current-tags>
<email>jennifer@zendesk.com</email>
<is-verified type="boolean">false</is-verified>
<photo-url>http://onlinesolutions.zendesk.com/images/types/user_sm.png</pho...>
<groups type="array"/>
</user>

January 17, 2012 00:56
User photo
Eric Neifert
csharpapi

Hi Aram,

Unfortunately I am no longer supporting this api. Perhaps someone else would be willing to take the project over?

My apoligies,

Eric

January 21, 2012 08:36
User photo
Matt Roybal
AtLast Fulfillment

I am trying to accomodate a possible response message of 503, jsut incase too many messages get returned in too quick of a time. I am unsure of where to check for this 503 for example say GetAllTicketsInView, because it appears that just a list of tickets is returned. Any help is greatly appreciated, thanks!

February 01, 2012 13:03
User photo
sho aga

Hey Eric,

My requirement is to show the search result from zendesk into my application. I have search option in my application and want to fetch any post with matching parameter in any forum of my zendesk account.

 

I added below function in entriesAndPost.cs file:

public List<Entry> GetEntriesBySearch(string searchText)
        {
            var request = new ZenRestRequest
            {
                Method = Method.GET,
                Resource = string.Format("search.xml?query=type:entry+subject:{0}", searchText)
            };

            return Execute<List<Entry>>(request);
        }

 

I want to search in any entry for matching subject.

 

this above function using below function from core.cs to get the data:

public T Execute<T>(ZenRestRequest request) where T : new()
        {
            var response = _client.Execute<T>(request);
            return response.Data;
        }

The problem I am facing here is it is not giving me anything via "response.Data", while if I check the value in "content" it has all the result in it.

 

I think this is because request for

"search.xml?"

returns result in records heirarchy in xml file like below:

 

<?xml version="1.0" encoding="UTF-8"?>
<records type="array" count="1">
  <record>
    <body>&lt;p&gt;pls explain.... asap&lt;/p&gt;</body>
    <created-at type="datetime">2012-02-28T17:53:35+06:00</created-at>
 .

.

.


  </record>
</records>

above mentioned xml data is also present in content of response.

 

Can you please help me out of this.

 

Thanks in advance.

Shobhit Agarwal

February 28, 2012 08:46
User photo
prathap kumar

Hi Eric,

We can take it forward for supporting the API.

Do you have any basic internal documentation

http://wisentechnologies.com/it-courses/.net-training.aspx

December 03, 2012 05:03
User photo
Eric Neifert
csharpapi

Hi Prathap,

I am just about done writing an updated version of the api and it can be found here: https://github.com/eneifert/ZendeskApi_v2. It is totally tested and working although I still want to add async support for mobile devices (note you will have to put in your own settings for the tests to pass). The documentation there is all I have but if you have any questions you can feel free to ask. 

 

Eric

December 03, 2012 05:15
User photo
Khaw How Cheng
cherrycredits

Hi Eric,

I try to use the latest Zendesk Api V2 .net 3.5 to update custom fields.

The following is my code:

var ticket = new Ticket()
{
Subject = TextBoxSubject.Text.Replace("&", "and").Replace("<", "(").Replace(">", ")"),
Description = TextBoxMessage.Text.Replace("&", "and").Replace("<", "(").Replace(">", ")"),
Priority = TicketPriorities.Normal,
Requester = new Requester(){Email = UserEmailID},
Comment = new Comment()
{
Body = TextBoxMessage.Text.Replace("&", "and").Replace("<", "(").Replace(">", ")"),
Public = true
},
};

ticket.CustomFields.Add(new CustomField { Id = Convert.ToInt32(ZendeskStatusID), Value = "pending"});
ticket.CustomFields.Add(new CustomField { Id = Convert.ToInt32(ZendeskCategoryID), Value = DropDownList2.SelectedValue });
ticket.CustomFields.Add(new CustomField { Id = Convert.ToInt32(ZendeskPaidUserID), Value = strPaiduser });
ticket.CustomFields.Add(new CustomField { Id = Convert.ToInt32(ZendeskcID), Value = UserCID });

 

var response = api.Tickets.CreateTicket(ticket).Ticket;
ticketID = response.Id.ToString();

But  it always return error Object reference not set to an instance of an object when the system run the code till ticket.CustomFields.Add.

May I know what is wrong?
Please advice. Thanks.

January 10, 2013 01:49
User photo
Eric Neifert
csharpapi

Hi Khaw How Cheng,

The problem is that the CustomFields collection is not initialized by default (this is due to the way the api handles null values verses empty values). So you could just add the following line before the first  "ticket.CustomFields.Add"

ticket.CustomFields = new List<CustomField>();

Also note that Zendesk made some changes this week and I have updated the api to reflect those. So make sure to get the latest if you are having any other problems.

Cheers,

Eric

January 11, 2013 09:14
User photo
Eric Neifert
csharpapi

Also for future support requests, please post them here: https://github.com/eneifert/ZendeskApi_v2/issues

January 11, 2013 09:28