Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@jakobt
Created January 19, 2015 20:06
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jakobt/b7400463e90e16928f57 to your computer and use it in GitHub Desktop.
Save jakobt/b7400463e90e16928f57 to your computer and use it in GitHub Desktop.
Consuming WooCommerce REST API from C#
//C# port of the https://github.com/kloon/WooCommerce-REST-API-Client-Library
//Including handling of woocommerce insisting on uppercase UrlEncoded entities
public class WoocommerceApiClient
{
private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
private string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length*2);
foreach (byte b in hash)
{
// can be "x2" if you want lowercase
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
public const string API_ENDPOINT = "wc-api/v1/";
public string ApiUrl { get; set; }
public string ConsumerSecret { get; set; }
public string ConsumerKey { get; set; }
public bool IsSsl { get; set; }
public WoocommerceApiClient(string consumerKey, string consumerSecret, string storeUrl, bool isSsl = false)
{
if (string.IsNullOrEmpty(consumerKey) || string.IsNullOrEmpty(consumerSecret) ||
string.IsNullOrEmpty(storeUrl))
{
throw new ArgumentException("ConsumerKey, consumerSecret and storeUrl are required");
}
this.ConsumerKey = consumerKey;
this.ConsumerSecret = consumerSecret;
this.ApiUrl = storeUrl.TrimEnd('/') + "/" + API_ENDPOINT;
this.IsSsl = isSsl;
}
public string GetAllProducts()
{
return MakeApiCall("products", new Dictionary<string, string>() {{"filter[limit]", "2000"}});
}
public string GetProducts()
{
return MakeApiCall("products");
}
private string MakeApiCall(string endpoint, Dictionary<string, string> parameters = null, string method = "GET")
{
if (parameters == null)
{
parameters = new Dictionary<string, string>();
}
parameters["oauth_consumer_key"] = this.ConsumerKey;
parameters["oauth_timestamp"] =
DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString();
parameters["oauth_timestamp"] = parameters["oauth_timestamp"].Substring(0,
parameters["oauth_timestamp"].IndexOf("."));
parameters["oauth_nonce"] = Hash(parameters["oauth_timestamp"]);
parameters["oauth_signature_method"] = "HMAC-SHA256";
parameters["oauth_signature"] = GenerateSignature(parameters, method, endpoint);
WebClient wc = new WebClient();
StringBuilder sb = new StringBuilder();
foreach (var pair in parameters)
{
sb.AppendFormat("&{0}={1}", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value));
}
var url = this.ApiUrl + endpoint + "?" + sb.ToString().Substring(1).Replace("%5b","%5B").Replace("%5d","%5D");
var result = wc.DownloadString(url);
return result;
}
private string GenerateSignature(Dictionary<string, string> parameters, string method, string endpoint)
{
var baserequesturi = Regex.Replace(HttpUtility.UrlEncode(this.ApiUrl + endpoint), "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper());
var normalized = NormalizeParameters(parameters);
var signingstring = string.Format("{0}&{1}&{2}", method, baserequesturi,
string.Join("%26", normalized.OrderBy(x => x.Key).ToList().ConvertAll(x => x.Key + "%3D" + x.Value)));
var signature =
Convert.ToBase64String(HashHMAC(Encoding.UTF8.GetBytes(this.ConsumerSecret),
Encoding.UTF8.GetBytes(signingstring)));
Console.WriteLine(signature);
return signature;
}
private Dictionary<string, string> NormalizeParameters(Dictionary<string, string> parameters)
{
var result = new Dictionary<string, string>();
foreach (var pair in parameters)
{
var key = HttpUtility.UrlEncode(HttpUtility.UrlDecode(pair.Key));
key = Regex.Replace(key, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()).Replace("%", "%25");
var value = HttpUtility.UrlEncode(HttpUtility.UrlDecode(pair.Value));
value = Regex.Replace(value, "(%[0-9a-f][0-9a-f])", c => c.Value.ToUpper()).Replace("%", "%25");
result.Add(key, value);
}
return result;
}
}
@IcuScc
Copy link

IcuScc commented Apr 18, 2015

Hi Jakobt,
I'm trying to make a POST and PUT, for update order status for example, but i dont got it.
Can you help me?
Thanks

@manojtiwari007
Copy link

jakobt,
I am trying execute a POST method to create product but it always return Bad Request.
Please help....
Thanks

@spielinger
Copy link

Hi Jakob.
When trying to request other endpoints, for example
/products/count
/products/categories/{id}
the calls could not be oauth authenticated because of a wrong signature. I did not yet fully understand what you are doing in the GenerateSignature method, but the problems seem to be there. Could you try the above endpoints and maybe find or explain the problem...
Thanks

@LilianDyer
Copy link

The GenerateSignature is generating a good signature. In my case, the problem was after it comes back, the HttpUtility.UrlEncode will encode the signature to lower case hex. So if it contains a '+' it will encode it to '%2b' but Woo Commerce is expecting '%2B'.

@shahshyam
Copy link

Hi ALL,
I completed GET,POST,DELETE and PUT operation in Woocommerce using C#. Let me know if anyone need help
Bsic Req: https enable

@itzRamkumar
Copy link

I am trying to update the status of an order. Here is the code i tried...

string orders = client.updateOrderStatus("180");

public string updateOrderStatus(string orderNo)
{
return updateStatus("orders/" + orderNo);
}

private string updateStatus(string endpoint, Dictionary<string, string> parameters = null, string method = "PUT")
{
if (parameters == null)
{
parameters = new Dictionary<string, string>();
}
parameters["oauth_consumer_key"] = this.ConsumerKey;
parameters["oauth_timestamp"] =
DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString();
parameters["oauth_timestamp"] = parameters["oauth_timestamp"].Substring(0,
parameters["oauth_timestamp"].IndexOf("."));
parameters["oauth_nonce"] = Hash(parameters["oauth_timestamp"]);
parameters["oauth_signature_method"] = "HMAC-SHA256";
parameters["oauth_signature"] = GenerateSignature(parameters, method, endpoint);
WebClient wc = new WebClient();
StringBuilder sb = new StringBuilder();
foreach (var pair in parameters)
{
sb.AppendFormat("&{0}={1}", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value));
}
var url = this.ApiUrl + endpoint + "?" + sb.ToString().Substring(1).Replace("%5b", "%5B").Replace("%5d", "%5D");
//var result = wc.DownloadString(url);
wc.UploadString(url, "{"order":{"status":"completed"}}");
return "";
}

It will throw the Exception

[WebException: The remote server returned an error: (401) Unauthorized.]
System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request) +309
System.Net.WebClient.UploadString(Uri address, String method, String data) +172
System.Net.WebClient.UploadString(String address, String data) +34
API.WoocommerceApiClient.updateStatus(String endpoint, Dictionary`2 parameters, String method) in E:\C# Mini Projects\API\API\WoocommerceApiClient.cs:126
API.WoocommerceApiClient.updateStatus1(String orderNo) in E:\C# Mini Projects\API\API\WoocommerceApiClient.cs:76
API.WebForm1.Page_Load(Object sender, EventArgs e) in E:\C# Mini Projects\API\API\WebForm1.aspx.cs:23
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +91
System.Web.UI.Control.LoadRecursive() +74
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207

Help to solve this.. I am using v2 Endpoint

@manisha0510
Copy link

@shahshyam I am trying to do GET, PUT, POST and DELETE operations on WooCommerce using C#. It would be great if you could help me.

@itzRamkumar
Copy link

@manisha0510 the above code will work for GET Method u can check that.. In PUT Method it returns an error.

@manisha0510
Copy link

@itzRamkumar I am getting 404NotFound even for GET method

@shahshyam
Copy link

yes, Woocommerce performs PUT Operation in https enable site.

@shahshyam
Copy link

I have wrapper for CRUD operation. If you are here let me contact for small donation

@itzRamkumar
Copy link

@shahshyam how to run PUT Method in localhost.. I just learned let me how it works..

@manisha0510 If u finish the PUT method please share the code it may help to others..

@TOuhrouche
Copy link

I am really having hard time even to get the GET request working :(
I am receiving an HTTP/1.1 302 Found all the time. Anyone faced this issue before?

@Groot90
Copy link

Groot90 commented Nov 29, 2015

Recently, I have tried quite a few things to solve numerous issues connecting to my WC API. In the end, this library was my ultimate choice. However, it seems that it lacks compatibility with v3 version of WC API. All you need to do to be able to connect to v3 API is this: Just add a "&" sign to consumer key at line 89! I have made a VB.NET v3 port of this nice library, with an additional try / catch block to catch the full exception code. You can check it here: http://www.softwarehorizont.com/2015/11/woocommerce-api-v3-vbnet-c-library.html . Hope it helps someone!

@Rey68
Copy link

Rey68 commented Dec 3, 2015

Hi:
I have this error in the code:
Excepción no controlada del tipo 'System.ArgumentOutOfRangeException' en mscorlib.dll

Additional information: Length can not be less than zero. Line 71

Why?

@diegoaraujolima
Copy link

i have problems with PUT. Anyone can post example?

@Groot90
Copy link

Groot90 commented Dec 4, 2015

@diegoaraujolima:

You can use WebClient's UploadData method (instead of DownloadString).

Something like this (VB.NET):

'uploadData is for the body of http PUT request (for example, JSON data )

Dim dataArr() As Byte = Encoding.UTF8.GetBytes(uploadData)
wc.UploadData(url, "PUT", dataArr)

@Rey68:

Are you sure the error is exactly at line 71? It looks like your parameters[] array is empty.

@diegoaraujolima
Copy link

@Groot90, I did what you suggested, but occours the error 403. Can you help me?

@Groot90
Copy link

Groot90 commented Dec 4, 2015

@diegoaraujolima
That error is probably related to your server's configuration. Maybe this thread could help: woocommerce/woocommerce#6529

@diegoaraujolima
Copy link

Resolved. Add Header wc.Headers.Add("Content-Type", "application/json");. Works! Thankz!

@Groot90
Copy link

Groot90 commented Dec 4, 2015

@diegoaraujolima
Great! Glad to hear you've fixed it.

To everyone:
Be sure that line #65 is using the proper time delimiter for your time zone. It can be a dot, but it also can be a comma character.

@putuyoga
Copy link

putuyoga commented Jan 5, 2016

For anyone who want to simplify the things, just use WoocommerceSharp

@danielgamajpa
Copy link

To use the PUT / POST I created a new method (named for MakeApiCallPUT ()) and function equivalent to line 77

var result = wc.DownloadString (url);
I put:
var result = wc.UploadString (url, "PUT", dadosJSON);

where dadosJSON is JSON content that will be sent to update.

Full function was as follows:

 private string MakeApiCallPUT(string endpoint, string dadosJSON = null, string method = "PUT")
        {

            Dictionary<string, string> parameters = null;

            if (parameters == null)
            {
                parameters = new Dictionary<string, string>();
            }
            parameters["oauth_consumer_key"] = this.ConsumerKey;

            //parameters["oauth_timestamp"] = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds.ToString();
            //parameters["oauth_timestamp"] = parameters["oauth_timestamp"].Substring(0, parameters["oauth_timestamp"].IndexOf(","));

            parameters["oauth_timestamp"] = ((DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1).Ticks) / (1000 * 10000)).ToString();

            parameters["oauth_nonce"] = Hash(parameters["oauth_timestamp"]);
            parameters["oauth_signature_method"] = "HMAC-SHA256";
            parameters["oauth_signature"] = GenerateSignature(parameters, method, endpoint);
            WebClient wc = new WebClient();
            StringBuilder sb = new StringBuilder();

            foreach (var pair in parameters)
            {
                sb.AppendFormat("&{0}={1}", HttpUtility.UrlEncode(pair.Key), HttpUtility.UrlEncode(pair.Value));
            }
            var url = this.ApiUrl + endpoint + "?" + sb.ToString().Substring(1).Replace("%5b", "%5B").Replace("%5d", "%5D").Replace("%7b", "%7B").Replace("%7d", "%7D").Replace("%3a", "%3A").Replace("%2c", "%2C");
            //var result = wc.DownloadString(url);
            var result = wc.UploadString(url, "PUT", dadosJSON);
            return result;
        }

@shahshyam
Copy link

Hi
I have Create Product , Customer and many other item in woocommerce . Please contact me https://www.upwork.com/users/~01b266b20bfa60411d

@kapildesai
Copy link

Can any body provide a solution for PUT or POST errors....Not able to solve the same......I can Fetch the products but cannot Update a product.

@shahshyam
Copy link

@kapildesai I will help you

@mbrn01
Copy link

mbrn01 commented Sep 7, 2017

@shahshyam can you help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment