Accessing the Canada Post Sell Online API using curl

Accessing the Canada Post Sell Online API using curl

By devin, 23 September, 2014

I've been trying to access the Canada Post Sell Online API (if it's even still called that, in 2014) and I'm having lots of trouble. I'm using an Ubercart module (uc_canadapost) and it doesn't seem to work or something. It looks like you used to get a Merchant ID when you used Sell Online, and with Canada Post's new APIs you get a username and password as your API key.

It took me a good 2 hours to figure out how to successfully use curl to access the REST API. I'm now going to document the examples of successful curl commands that have actually worked.

First, go to https://www.canadapost.ca/cpotools/apps/drc/registered?execution=e4s1 and get your API Key. I'm using my development API key, which is broken into a username field and a password field, separated by a colon. I tried using the -H flag to curl to send the Basic Authorization header, which didn't work. I must have done it wrong. It was much easier (and more successful) to use the -u flag for the authentication bit.

This page https://www.canadapost.ca/cpo/mc/business/productsservices/developers/s… was a bunch of helpful information sandwiched between useless information. The relevant bit was that you can't just find a URL and send an HTTP GET and get your response. There are mandatory and optional HTTP headers; I'm reproducing the mandatory ones here:

HTTP Header Variable Applicable Methods Mandatory / Optional Value Description

Authorization

GET, POST, DELETE

Mandatory

Basic userid:password

  • The word "Basic" is a literal value that must be present.
  • A single space follows the word Basic.
  • The API key follows the space as a single Base64-encoded string (52 characters).
  • The encoded string is generated from the API key (a concatenation of the userid, a colon and the password)
  • For an example of a utility that can generate the Base64-encoded string from your userid and password parts, see Test Tools .

Content-Type

POST

Mandatory

Unique per service group. See service documentation for details.

This is the XML version of the body you are sending in the POST.

( Note: */* in place of the header value will return an error)

Accept

GET

Mandatory

Unique per service group. See service documentation for details or use "media-type" from the provided link.

This is the XML version of the response that you are expecting to receive.

( Note: */* in place of the header value will return an error)

So for a HTTP GET, you need the Authorization header and the Accept header.

Let's try this for a simple query. There is a list of queries here: http://www.canadapost.ca/cpo/mc/business/productsservices/developers/se…

Here's how I did that for a simple query to "discover services" using GET(documentation for this call is here: http://www.canadapost.ca/cpo/mc/business/productsservices/developers/se…).

curl -u "edc2833333333335:dc167444444444444444a3" -H "Accept: application/vnd.cpc.ship.rate-v3+xml" 'https://ct.soa-gw.canadapost.ca/rs/ship/service?country=CA'

This was the magic. I used my development API Key (you can see I've obscured most of it with 3s and 4s) and I sent the request to the development version of the URL (ct.soa-gw.canadapost.ca instead of just soa-gw.canadapost.ca). I got this response back:

<?xml version="1.0" encoding="UTF-8"?>
<services xmlns="http://www.canadapost.ca/ws/ship/rate-v3">
	<service><service-code>DOM.EP</service-code><service-name>Expedited Parcel</service-name><link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.EP?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/></service>

	<service><service-code>DOM.RP</service-code><service-name>Regular Parcel</service-name><link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.RP?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/></service>

	<service><service-code>DOM.PC</service-code><service-name>Priority</service-name><link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.PC?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/></service>

	<service><service-code>DOM.XP</service-code><service-name>Xpresspost</service-name><link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.XP?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/></service>
</services>

 

Woohoo! Now to get rates via POST. The Canada Post documentation is here: http://www.canadapost.ca/cpo/mc/business/productsservices/developers/se…. I've translated it into curl syntax:

curl -X POST -u "edc2833333333335:dc167444444444444444a3" -H "Accept: application/vnd.cpc.ship.rate-v3+xml" -H "Content-Type: application/vnd.cpc.ship.rate-v3+xml" -d @post.xml https://ct.soa-gw.canadapost.ca/rs/ship/price

Now the rubber hits the road here - -d @post.xml means I'm sending the data contained in the post.xml file in my current directory. You can include it as a big string (e.g. -d '

<?xml version="1.0" encoding="utf-8"?> 

	<mailing-scenario xmlns="http://www.canadapost.ca/ws/ship/rate-v3"> 

	  <quote-type>counter</quote-type> 

	  <origin-postal-code>N2G1V6</origin-postal-code> 

	  <destination> 

	    <domestic><postal-code>K0J1X0</postal-code></domestic> 

	  </destination> 

	  <services> 

	    <service-code>DOM.RP</service-code> 

	    <service-code>DOM.EP</service-code> 

	    <service-code>DOM.XP</service-code> 

	  </services> 

	  <parcel-characteristics> 

	    <weight>2</weight> 

	  </parcel-characteristics> 

	</mailing-scenario>

...and that beast, sent along with the CURL POST above it, gives us the following response. We did it!

<?xml version="1.0" encoding="UTF-8"?>

<price-quotes xmlns="http://www.canadapost.ca/ws/ship/rate-v3">
<price-quote>

	<service-code>DOM.RP</service-code>
	<service-link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.RP?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/>
	<service-name>Regular Parcel</service-name>

	<price-details>
		<base>12.88</base>
		<taxes><gst>0.00</gst><pst>0.00</pst><hst percent="13.000">1.79</hst></taxes>
		<due>15.54</due>

		<options><option><option-code>DC</option-code><option-name>Delivery confirmation</option-name><option-price>0</option-price><qualifier><included>true</included></qualifier></option></options>

		<adjustments><adjustment><adjustment-code>FUELSC</adjustment-code><adjustment-name>Fuel surcharge</adjustment-name><adjustment-cost>0.87</adjustment-cost><qualifier><percent>6.75</percent></qualifier></adjustment></adjustments>

	</price-details>

	<weight-details></weight-details>

	<service-standard><am-delivery>false</am-delivery><guaranteed-delivery>false</guaranteed-delivery><expected-transit-time>3</expected-transit-time><expected-delivery-date>2014-09-26</expected-delivery-date></service-standard>
</price-quote>
<price-quote>

	<service-code>DOM.XP</service-code>
	<service-link rel="service" href="https://ct.soa-gw.canadapost.ca/rs/ship/service/DOM.XP?country=CA" media-type="application/vnd.cpc.ship.rate-v3+xml"/>
	<service-name>Xpresspost</service-name>

	<price-details>
		<base>16.19</base>
		<taxes><gst>0.00</gst><pst>0.00</pst><hst percent="13.000">2.35</hst></taxes>
		<due>20.44</due>
		<options><option><option-code>DC</option-code><option-name>Delivery confirmation</option-name><option-price>0</option-price></option></options>

		<adjustments><adjustment><adjustment-code>FUELSC</adjustment-code><adjustment-name>Fuel surcharge</adjustment-name><adjustment-cost>1.90</adjustment-cost><qualifier><percent>11.75</percent></qualifier></adjustment></adjustments>
	</price-details>

	<weight-details></weight-details>

	<service-standard><am-delivery>false</am-delivery><guaranteed-delivery>true</guaranteed-delivery><expected-transit-time>2</expected-transit-time><expected-delivery-date>2014-09-25</expected-delivery-date></service-standard>
</price-quote>
</price-quotes>

Plain text

  • No HTML tags allowed.
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.