Difference between revisions of "Rest API"

From Rackspace Email & Apps API
Jump to: navigation, search
(Updated to reflect latest live version.)
(Operations)
 
(19 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
== Recent Changes ==
 
== Recent Changes ==
  
'''11/22/09 '''
+
'''09/01/10 '''
 
{|
 
{|
 
|
 
|
 
New features:
 
New features:
*Index/Add/Delete Alternate Domains.
+
* Now Rackspace Email Mailboxes can be visible in Exchange Global Address List. And Exchange Mailboxes can be visible in Rackspace Email Company Directory.
*Show/Edit Domain Spam Settings.
+
* Now Index Rackspace Email/Exchange Mailbox can filter mailboxes by "enabled" flag.
*Index/Add/Delete Domain Blacklist/Safelist.
+
* Added "lastLogin" to Rackspace Email/Exchange Mailbox Show.
*Show/Edit Split Domain Routing.
+
|
*Show Mailbox ActiveSync Setup Info.
+
|}
 +
 
 +
'''08/01/10 '''
 +
{|
 +
|
 +
New features:
 +
* Added Rackspace Email Mailbox Contact info. See [[Rackspace_Mailbox_(Rest_API)| here]].
 +
* Added Create Login Token. See [[Customer_(Rest_API)#Create_Login_Tokens| here]].
 +
|
 +
|}
 +
 
 +
'''06/20/10 '''
 +
{|
 +
|
 +
New features:
 +
* Added [[Rackspace_Alias(Rest_API)| Rackspace Email Alias]].
 
|
 
|
 
|}
 
|}
  
  
== Introduction ==
+
'''06/11/10 '''
 +
{|
 +
|
 +
New features:
 +
* Added Rackspace Email Mailbox Spam Settings/Blacklist/Safelist. See [[Rackspace_Mailbox_Spam_(Rest_API)| here]].
 +
* Now Rackspace Email Mailbox can Show/Edit vacation message and email forwarding address. See [[Rackspace_Mailbox_(Rest_API)| here]].
 +
* Added SharePoint Service Settings. See [[SharePoint_(Rest_API)| here]].
 +
|
 +
|}
  
The Email & Apps Control Panel API provides most of the functions of the Control Panel through a HTTP-based REST API ([http://en.wikipedia.org/wiki/Application_programming_interface Application Programming Interface]). Whether it is adding a new customer account, adding mailboxes, or any other of the supported features the API allows your application to administer the changes regardless of your application's language or nature. For more information on RESTful web services refer to the following sites:
 
  
http://en.wikipedia.org/wiki/Representational_State_Transfer
+
== Introduction ==
  
http://java.sun.com/developer/technicalArticles/WebServices/restful/
+
The Email & Apps Control Panel API provides most of the functions of the Control Panel through a REST-based [http://en.wikipedia.org/wiki/Web_service web API]. Whether it is adding a new customer account, adding mailboxes, or any other of the supported features the API allows your application to administer the changes regardless of your application's language or nature. For more information on RESTful web services refer to the following sites:
  
 +
[http://www.peej.co.uk/articles/restfully-delicious.html Paul James's Homepage: A RESTful Web service, an example]
  
The API is accessible to resellers only. As of now, most of the supported functions manage only customers, domains, and Exchange accounts.
+
[http://en.wikipedia.org/wiki/Representational_State_Transfer#External_links Wikipedia: Representational State Transfer - External Links]
  
  
 +
The API is accessible to all with access to Control Panel, including resellers, business customers, enterprise customers, and indirect customers. However, not all operations are available to non-resellers. See the [[Rest_API#Operations|Operations]] section for more details.
  
 
== Operations ==
 
== Operations ==
  
The following pages detail the operations that the API supports. The operations are grouped into sections based on the entity/object types that each operation interacts with.
+
The following pages detail the operations that the API supports. The operations are grouped into sections based on the entity/object types that each operation interacts with. Non-resellers do not have access to all functions.
  
 
{| class="wikitable"
 
{| class="wikitable"
 
!Resource
 
!Resource
 
!Example URI
 
!Example URI
 +
!Business User Access
 
|-
 
|-
 
| [[Customer_(Rest_API)| Customer]]
 
| [[Customer_(Rest_API)| Customer]]
 
| /customers/123456789
 
| /customers/123456789
 +
| [[Customer_(Rest_API)#Create_Login_Tokens| Create Login Token]]
 +
|-
 +
| [[DKIM (Rest_API)| DKIM]]
 +
| /customers/123456789/domains/example.com/dkim/enable
 +
| All
 
|-
 
|-
 
| [[Domain_(Rest_API)| Domain]]
 
| [[Domain_(Rest_API)| Domain]]
 
| /customers/123456789/domains/example.com
 
| /customers/123456789/domains/example.com
 +
| [[Domain_(Rest_API)#Index| Index]], [[Domain_(Rest_API)#Show| Show]], [[Domain_(Rest_API)#Split Domain Routing| Split Domain Routing]], [[Domain_(Rest_API)#Archiving SSO Login URL| Archiving SSO Login URL]], [[Domain_(Rest_API)#Domain Public Folders|Domain Public Folders ]]
 +
|-
 +
| [[Domain_Spam_(Rest_API)| Domain Spam Settings]]
 +
| /customers/123456789/domains/example.com/spam/settings
 +
| All
 +
|-
 +
| [[Rackspace_Mailbox_(Rest_API)|  Rackspace Email Mailbox]]
 +
|  /customers/123456789/domains/example.com/rs/mailboxes/john.smith
 +
| All
 +
|-
 +
| [[Rackspace_Mailbox_Spam_(Rest_API)| Rackspace Email Mailbox Spam Settings]]
 +
|  /customers/123456789/domains/example.com/rs/mailboxes/john.smith/spam
 +
| All
 +
|-
 +
| [[Rackspace_Alias(Rest_API)|  Rackspace Email Alias]]
 +
|  /customers/123456789/domains/example.com/rs/mailboxes/john.smith/alias
 +
| All
 
|-
 
|-
| [[Mailbox_(Rest_API)| Exchange Mailbox]]
+
| [[Exchange_Mailbox_(Rest_API)| Exchange Mailbox]]
 
| /customers/123456789/domains/example.com/ex/mailboxes/john.smith
 
| /customers/123456789/domains/example.com/ex/mailboxes/john.smith
 +
| All
 +
|-
 +
| [[Exchange_Mailbox_Spam_(Rest_API)| Exchange Mailbox Spam Settings]]
 +
| /customers/123456789/domains/example.com/ex/mailboxes/john.smith/spam
 +
| All
 
|-
 
|-
| [[Contact_(Rest_API)| Exchange Contact]]
+
| [[Exchange_Contact_(Rest_API)| Exchange Contact]]
 
| /customers/123456789/domains/example.com/ex/contacts/john.smith
 
| /customers/123456789/domains/example.com/ex/contacts/john.smith
 +
| All
 
|-
 
|-
| [[Distribution_List_(Rest_API)| Exchange Distribution List]]
+
| [[Exchange_Distribution_List_(Rest_API)| Exchange Distribution List]]
 
| /customers/123456789/domains/example.com/ex/distributionlists/group.name
 
| /customers/123456789/domains/example.com/ex/distributionlists/group.name
 +
| All
 +
|-
 +
| [[Exchange_Resource_Mailbox_(Rest_API)| Exchange Resource Mailbox]]
 +
| /customers/123456789/domains/example.com/ex/resources/conference.room
 +
| All
 +
|-
 +
| [[SharePoint_(Rest_API)| SharePoint]]
 +
| /customers/123456789/sharepoint/settings
 +
| [[SharePoint_(Rest_API)#Show | Show]]
 
|}
 
|}
  
Line 56: Line 118:
 
== Quick Start ==
 
== Quick Start ==
  
To get a list of mailboxes under a domain:
+
'''What you need:'''
 +
* A Rackspace Email and Apps Control Panel admin account
 +
* A HTTP class library that supports TLS and the HTTP methods: GET, POST, PUT, DELETE.
 +
 
  
First, you need to populate some HTTP headers with the correct information. 'Accept' needs to be either 'text/xml' or 'application/json' to indicate the format of the returned data. 'User-Agent' just needs to be any name you choose to identify your client with. 'X-Api-Signature' needs a
+
'''Making your first API call, an Show Customer request:'''
 +
# Obtain your API keys
 +
#:* Click on My Account at the top of the [https://apps.rackspace.com/?cp Control Panel web interface]. Under the Administrators heading there will be an link for the API keys page.
 +
# Set up your client's HTTP request
 +
#:* Set up your client to make calls to a URL beginning with <nowiki>https://api.emailsrvr.com/v0</nowiki>.
 +
#:* Populate the Accept, User-Agent and X-Api-Signature HTTP request headers correctly. This is explained in detail [[#HTTP Headers|here]].
 +
# Make a GET request to /customers/me.
 +
#:* The complete URI will be <nowiki>https://api.emailsrvr.com/v0/customers/me</nowiki>. Use your HTTP library to retrieve the HTTP response code, 'x-error-message' HTTP response header and HTTP response body so that they may be displayed to help debug and determine success.
 +
'''From here:'''
 +
* Learn about the operations you'll be implementing at the subpages [[#Operations|here]].
  
 
== Accessing the API ==
 
== Accessing the API ==
Line 89: Line 163:
 
| v0 (current)
 
| v0 (current)
 
| <nowiki>https://api.emailsrvr.com/v0/</nowiki>
 
| <nowiki>https://api.emailsrvr.com/v0/</nowiki>
| http://signup.apps.rackspace.com/api-wiki/index.php/Rest_API
+
| http://api-wiki.apps.rackspace.com/api-wiki/index.php/RestAPI
 
|}
 
|}
  
Line 114: Line 188:
 
=== Authentication ===
 
=== Authentication ===
  
To gain access to the API, your request must include a properly constructed X-Api-Signature HTTP header. Details on what to put in the header are below. To construct the header, you must have the following keys that that are generated from the Control Panel Web interface.
+
To gain access to the API, your request must include a properly constructed X-Api-Signature HTTP header. Details on what to put in the header are below. To construct the header, you must have the following keys that that are generated from the [https://apps.rackspace.com/?cp Control Panel Web interface]. The key generation page can be found by clicking 'My Account' at the top, then 'Generate API Keys' in the Administrators section.
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 138: Line 212:
  
 
Format is as follows:
 
Format is as follows:
<'''User Key'''>:<'''Timestamp'''>:<'''Signature'''><br>
+
<'''User Key'''>:<'''Timestamp'''>:<'''SHA1 Hash'''><br>
Example: ''eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=''
+
Example: ''eGbq9/2hcZsRlr1JV1Pi:20010317143725:46VIwd66mOFGG8IkbgnLlXnfnkU=''
  
 
Remember to include the colons between the data strings!
 
Remember to include the colons between the data strings!
Line 149: Line 223:
 
<br>
 
<br>
 
'''Timestamp''':<br>
 
'''Timestamp''':<br>
The format is YYYYMMDDHHmmssff. All values besides year are zero-padded to two spaces. For example, March 08th 2001 at 2:37.25pm would be ''20010308143725''.
+
The format is YYYYMMDDHHmmss. All values besides year are zero-padded to two spaces. For example, March 08th 2001 at 2:37.25pm would be ''20010308143725''.
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 169: Line 243:
 
| ss
 
| ss
 
| Second
 
| Second
|-
 
| ff
 
| Millisecond
 
 
|}
 
|}
  
  
<br>
+
'''SHA1 Hash''':
'''Signature''':
 
  
 
A SHA1 (Secure Hash Algorithm) hash must be applied to a string with the following information:
 
A SHA1 (Secure Hash Algorithm) hash must be applied to a string with the following information:
Line 182: Line 252:
 
<'''User Key'''><'''User Agent'''><'''Timestamp'''><'''Secret Key'''>
 
<'''User Key'''><'''User Agent'''><'''Timestamp'''><'''Secret Key'''>
  
Note that the 'User Agent' must be the exact same as what is specified in the User-Agent HTTP Header. Using the above example data, the string before hashing is:<br>''eGbq9/2hcZsRlr1JV1PiRackspace Management Interface20010308143725QHOvchm/40czXhJ1OxfxK7jDHr3t''
+
Note that the 'User Agent' must be the exact same as what is specified in the User-Agent HTTP header. Using the above example data, the string before hashing is:<br>''eGbq9/2hcZsRlr1JV1PiRackspace Management Interface20010308143725QHOvchm/40czXhJ1OxfxK7jDHr3t''
  
 
Resulting base-64 SHA1 Hash:<br>''46VIwd66mOFGG8IkbgnLlXnfnkU=''
 
Resulting base-64 SHA1 Hash:<br>''46VIwd66mOFGG8IkbgnLlXnfnkU=''
  
 
Be sure to encode the binary hash, not the hex hash, into base-64. The resulting string should be 28 characters long.
 
Be sure to encode the binary hash, not the hex hash, into base-64. The resulting string should be 28 characters long.
 
  
 
== Using the API ==
 
== Using the API ==
Line 193: Line 262:
 
=== Requests ===
 
=== Requests ===
  
HTTP requests should be sent to the server with the correct URL, HTTP Method, HTTP Headers and form data (if needed). The URLs, corresponding HTTP Methods, and necessary form data for the desired operations are detailed in the [[#Operations|operation pages]].
+
HTTP requests should be sent to the server with the correct URL, HTTP method, HTTP headers and form data (if needed). The URL specifies the resource, the HTTP method specifies what operation is done on the resource, and form data is used to specify the details of the resource when the resource is added or edited.
  
 +
The URLs, corresponding HTTP methods, and necessary form data for the desired operations are detailed in the [[#Operations|operation pages]].
 +
 +
 +
If you're getting the HTTP status code 417 see [[Handling HTTP code 417:  Expectation failed]]
  
 
==== URL ====
 
==== URL ====
  
 
The URLs are specifies the resource or resource collection. Objects are organized in a tree collection, starting with customers at the top, then domains, then domain objects next (such as mailboxes, contacts, and distribution lists) and so on. The URLs of the resources and collections accessible are found on the operation pages.
 
The URLs are specifies the resource or resource collection. Objects are organized in a tree collection, starting with customers at the top, then domains, then domain objects next (such as mailboxes, contacts, and distribution lists) and so on. The URLs of the resources and collections accessible are found on the operation pages.
 
  
 
==== HTTP Method ====
 
==== HTTP Method ====
  
It is the HTTP Method that specifies what operation will be done on the resource. For example, to get the details of a mailbox a HTTP GET will be done on /customers/12345678/domains/example.com/ex/mailboxes/john.smith. If the mailbox does not exist, a HTTP POST to the same URL with the necessary form data will add the mailbox. Then, a HTTP PUT to the same URL will edit mailbox. And to delete the mailbox, an HTTP DELETE would be used.
+
It is the HTTP method that specifies what operation will be done on the resource. For example, to get the details of a mailbox a HTTP GET will be done on /customers/12345678/domains/example.com/ex/mailboxes/john.smith. If the mailbox does not exist, a HTTP POST to the same URL with the necessary form data will add the mailbox. Then, a HTTP PUT to the same URL will edit mailbox. And to delete the mailbox, an HTTP DELETE would be used.
  
The types of operations a certain method performs is consistent and is outlined in the table below.
+
The types of operations a certain method performs is outlined below.
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 237: Line 309:
 
!''Header Name''
 
!''Header Name''
 
!''Description''
 
!''Description''
!''Example''
+
!''Example Header Value''
 
|-
 
|-
 
| Accept
 
| Accept
| The requested content type (required regardless of type of operation). See [[#Formats|Response Formats]]
+
| The requested content type (required for Index and Show actions). Fill this with either 'text/xml' or 'application/json'. See [[#Formats|Response Formats]]
 
| ''text/xml''
 
| ''text/xml''
 
|-
 
|-
Line 252: Line 324:
 
|}
 
|}
  
 +
==== Form Data ====
  
 +
When using Add and Edit operations, the details of the resource are sent to the API server via HTTP form data. Your HTTP library should include methods for sending form data along with an HTTP request. The library should by default send the data in the HTTP request body using the 'application/x-www-form-urlencoded' data format.
  
 
+
==== Index Filter/Search ====
==== Filter/Search ====
 
  
 
The results of Index actions can be filtered/searched. The index URLs can take either one of the query strings: "?startswith=xx" or "?contains=xx," where "xx" is the key word. If the request specifies more than one of these two query strings, a 400 HTTP error will be returned. Different fields will be searched depending on the resource type, see below.
 
The results of Index actions can be filtered/searched. The index URLs can take either one of the query strings: "?startswith=xx" or "?contains=xx," where "xx" is the key word. If the request specifies more than one of these two query strings, a 400 HTTP error will be returned. Different fields will be searched depending on the resource type, see below.
Line 283: Line 356:
 
| Associated mailbox name, mailbox display name
 
| Associated mailbox name, mailbox display name
 
|}
 
|}
 
 
'''Reference Number'''
 
 
For the customer object only, the query string "referenceNumber=xx" searches for a customer with an exact reference number. The result if found is the detail page of the customer.
 
 
  
  
 
==== Throttling ====
 
==== Throttling ====
  
The server limits the number of requests allowed per user in a certain period of time.  The current limit is 1500 requests over 5 minutes. The number of requests made are logged per minute. Calls that were made correctly with a user's API key, but not completed for any reason, including those exceeding the throttle limit, are included in this count.
+
The server limits the number of requests allowed per user in a certain period of time.  The number of requests made are logged per minute. Calls that were made correctly with a user's API key, but not completed for any reason, including those exceeding the throttle limit, are included in this count.
  
 
If a user is over the throttling limit then a 403 HTTP code will be returned with an "Exceeded request limits" message.
 
If a user is over the throttling limit then a 403 HTTP code will be returned with an "Exceeded request limits" message.
  
 +
 +
{| class="wikitable"
 +
!''Operation Category''
 +
!''Request Limit''
 +
|-
 +
| GET
 +
| 60 per minute
 +
|-
 +
| PUT, POST, DELETE
 +
| 30 per minute
 +
|-
 +
| POST, PUT, DELETE on a domain
 +
| 2 per minute
 +
|-
 +
| POST, DELETE on alternate domains
 +
| 2 per minute
 +
|-
 +
| Enabling public folders for a domain
 +
| 1 per 5 minutes
 +
|}
  
  
 
==== Examples ====
 
==== Examples ====
  
Example requests:
+
Index of Exchange Mailboxes:
 
<pre>
 
<pre>
Index of Exchange Mailboxes:
 
 
 
Hypertext Transfer Protocol
 
Hypertext Transfer Protocol
 
     GET /v0/customers/12345678/domains/example.com/ex/mailboxes?size=100&offset=100 HTTP/1.1
 
     GET /v0/customers/12345678/domains/example.com/ex/mailboxes?size=100&offset=100 HTTP/1.1
        Request Method: GET
 
        Request URI: /v0/customers/12345678/domains/example.com/ex/mailboxes?size=100&offset=100
 
        Request Version: HTTP/1.1
 
 
     Host: api.emailsrvr.com
 
     Host: api.emailsrvr.com
 
     User-Agent: Rackspace Management Interface
 
     User-Agent: Rackspace Management Interface
 
     X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
 
     X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
 
     Accept: text/xml
 
     Accept: text/xml
 
+
</pre>
 
   
 
   
 
Adding New Exchange Mailbox:
 
Adding New Exchange Mailbox:
 
+
<pre>
 
Hypertext Transfer Protocol
 
Hypertext Transfer Protocol
 
     POST /v0/customers/12345678/domains/example.com/ex/mailboxes/john.smith HTTP/1.1
 
     POST /v0/customers/12345678/domains/example.com/ex/mailboxes/john.smith HTTP/1.1
        Request Method: POST
 
        Request URI: /v0/customers/12345678/domains/example.com/ex/mailboxes/john.smith
 
        Request Version: HTTP/1.1
 
 
     Host: api.emailsrvr.com
 
     Host: api.emailsrvr.com
 
     User-Agent: Rackspace Management Interface
 
     User-Agent: Rackspace Management Interface
 
     X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
 
     X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
    Accept: text/xml
 
 
     Content-Length: 53
 
     Content-Length: 53
 
         [Content length: 53]
 
         [Content length: 53]
Line 333: Line 411:
 
Line-based text data: application/x-www-form-urlencoded
 
Line-based text data: application/x-www-form-urlencoded
 
     size=2048&displayName=John%20Smith&password=abcABC123
 
     size=2048&displayName=John%20Smith&password=abcABC123
+
 
 
</pre>
 
</pre>
  
 +
=== Responses ===
  
 +
==== HTTP Status Code ====
  
 +
On a successfully executed request, a 200 HTTP Code is returned. If the request was unsuccessful however, an HTTP error code in the 400s or 500s will be returned.
  
=== Responses ===
+
==== HTTP Response Body ====
  
On a successfully executed request, a 200 HTTP Code is returned. Requested data is also returned if the operation was a Show or Index action. If the request is unsuccessful, then an error HTTP Code is returned with a message detailing the error. The errors and their corresponding codes are detailed on the operation pages.
+
If the request is an Index or Show request, the request data will be returned in the format specified in the HTTP Body.
  
==== Formats ====
+
===== Formats =====
  
Requests for data (index and show requests) are returned with XML or JSON data based on what your application populates the [[#HTTP_Headers|HTTP Accept Headers]] with.
+
Requests for data (index and show requests) are returned with XML or JSON data based on what your application populates the [[#HTTP_Headers|HTTP Accept headers]] with.
  
  
For XML, populate the header with 'text/xml' (ex: Headers!["Accept"] = "text/xml"). The XML document returned will conform to a published XSD (XML Schema Document). There are many ways to extract data from an XML document, but we have found that the [http://www.w3schools.com/XPath/default.asp XPath] tree-style traversal has served our purposes. In any case, your application will likely need to use a library with the functions necessary for whichever method you choose to use to extract data.
+
For XML, populate the header with 'text/xml' (ex: Headers!["Accept"] = "text/xml"). The XML document returned will conform to a published XSD (XML Schema Document). There are many ways to parse the data in an XML document, but we have found that the [http://www.w3schools.com/XPath/default.asp XPath] tree-style traversal has served our purposes. In any case, your application will likely need to use a class library for your chosen method.
  
  
 
For JSON, populate the header with 'application/json' (ex: Headers!["Accept"] = "application/json"). As with XML, a library will likely be needed to parse the data.
 
For JSON, populate the header with 'application/json' (ex: Headers!["Accept"] = "application/json"). As with XML, a library will likely be needed to parse the data.
 +
 +
==== HTTP Headers ====
 +
 +
The only data returned in the header is the error message (if any).
 +
 +
{| class="wikitable"
 +
!''Header Name''
 +
!''Description''
 +
!''Example Header Value''
 +
|-
 +
| x-error-message
 +
| The error message. See [[#Errors|Errors]].
 +
| Missing required field: name
 +
|}
  
 
==== Errors ====
 
==== Errors ====
  
If a request is not sucessfully completed an HTTP error code in the 400s or 500s will be returned. An error code of 500 generally indicates an error with our servers whereas an error code in the 400s is generally an error with the data sent to the server. In such cases the HTTP response will return a header named 'x-error-message'. Below are some errors that are common to many operations. Each operation also has some specific errors which are outlined with the operation.  
+
In the event of an error, the error message will be returned the HTTP header '''x-error-message''' and an HTTP Status Code in the '''400'''s or '''500'''s will be returned.
 +
 
 +
Note: Every language's HTTP library provides methods for retrieving HTTP response codes and response headers.
 +
 
 +
Below are some errors that are common to many operations. Each operation also has some specific errors which are outlined with the operation.  
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 365: Line 464:
 
|400
 
|400
 
|When requesting an index or show on a resource the 'Accept' header should be either 'text/xml' or 'application/json'
 
|When requesting an index or show on a resource the 'Accept' header should be either 'text/xml' or 'application/json'
 +
|-
 +
|Expectation  Failed: See [[Handling HTTP code 417: Expectation failed]]
 +
|417
 +
|(none)
 
|-
 
|-
 
|Customer account number is invalid
 
|Customer account number is invalid
Line 371: Line 474:
 
|-
 
|-
 
|Domain is not found
 
|Domain is not found
|404  
+
|404
 
|<domain name> not found
 
|<domain name> not found
 
|-
 
|-
Line 378: Line 481:
 
|Mailbox not found
 
|Mailbox not found
 
|-
 
|-
|Required form field is missing  
+
|Required form field is missing
|400  
+
|400
 
|Missing required field: <required field>
 
|Missing required field: <required field>
 
|-
 
|-
|Required form field has null or empty string input  
+
|Required form field has null or empty string input
|400  
+
|400
|Required field <required field> cannot be empty  
+
|Required field <required field> cannot be empty
 
|-
 
|-
|Integer form field has non-integer input  
+
|Integer form field has non-integer input
|400  
+
|400
|Invalid format for <field>, input must be an integer  
+
|Invalid format for <field>, input must be an integer
 
|-
 
|-
|Boolean form field has non-boolean input  
+
|Boolean form field has non-boolean input
|400  
+
|400
|Invalid format for <field>, input must be True or False  
+
|Invalid format for <field>, input must be True or False
 
|-
 
|-
|Form data has an unrecognized field  
+
|Form data has an unrecognized field
|400  
+
|400
 
|Unrecognized field: <field>
 
|Unrecognized field: <field>
 
|-
 
|-
Line 423: Line 526:
 
| This is the number of items to offset away from the first item in the list.
 
| This is the number of items to offset away from the first item in the list.
 
|}
 
|}
 +
 +
===== Example =====
 +
 +
A PHP Example of paging can be found [[PHP_Examples_(Rest_API)| here]].
 +
 +
==== Examples ====
 +
 +
<pre>
 +
HTTP/1.1 200 OK
 +
Cache-Control: private
 +
Content-Type: text/xml; charset=utf-8
 +
Server: Microsoft-IIS/7.0
 +
Date: Fri, 04 Dec 2009 19:08:11 GMT
 +
Content-Length: 430
 +
 +
<?xml version="1.0" encoding="utf-8"?>
 +
<domainList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:xml:domainList">
 +
  <offset>0</offset>
 +
  <size>50</size>
 +
  <total>1</total>
 +
  <domains>
 +
    <domain>
 +
      <name>customer.com</name>
 +
      <accountNumber>123456</accountNumber>
 +
      <serviceType>rsemail</serviceType>
 +
    </domain>
 +
  </domains>
 +
</domainList>
 +
</pre>
 +
 +
<pre>
 +
HTTP/1.1 404 Not Found
 +
Cache-Control: private
 +
Server: Microsoft-IIS/7.0
 +
x-error-message: Customer Not Found
 +
Date: Fri, 04 Dec 2009 19:13:59 GMT
 +
Content-Length: 0
 +
</pre>
 +
 +
<pre>
 +
HTTP/1.1 400 Bad Request
 +
Cache-Control: private
 +
Server: Microsoft-IIS/7.0
 +
x-error-message: Missing required field: type
 +
Date: Fri, 04 Dec 2009 19:17:29 GMT
 +
Content-Length: 0
 +
</pre>
  
  
 
== Examples ==
 
== Examples ==
 
  
 
=== Ruby ===
 
=== Ruby ===
Line 433: Line 582:
  
 
<pre>
 
<pre>
module NetMethods
+
require  'server.rb'
 +
 
 +
server = Server.new
 +
 
 +
response = server.get  '/customers', server.xml_format
 +
 
 +
#fields = Hash['serviceType' =>  'exchange', 'exchangeMaxNumMailboxes' => '4']
 +
#response =  server.post '/customers/me/domains/newdomain.com', fields
 +
 
 +
puts response.code
 +
puts response['x-error-message']
 +
puts response.body
 +
</pre>
 +
 
 +
<pre>
 +
require 'test/unit/assertions'
 +
require 'net/http'
 +
require 'date'
 +
require 'date/format'
 +
require 'digest/sha1'
 +
require 'base64'
 +
require 'time'
 +
 
 +
class Server
 +
  include Test::Unit::Assertions
 +
 
 +
  def initialize(server='api.emailsrvr.com', version_prefix='/v0', user_key='xxxxxxxxxxxxxxxxxxxx', secret_hash='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
 +
    @server = server
 +
    @version_prefix = version_prefix
 +
    @user_key = user_key
 +
    @secret_hash = secret_hash
 +
  end
 +
 
 +
# Response Type Enums
 +
 
 +
  def xml_format
 +
    'text/xml'
 +
  end
 +
 
 +
  def json_format
 +
    'application/json'
 +
  end
 +
 
 +
#
 +
# HTTP Request Verbs
 +
 
   def get(url_string, format)
 
   def get(url_string, format)
     url = URI.parse('https://' + server_host + server_port + version + url_string)
+
     uri = full_uri(url_string)
     @response = Net::HTTP::start(url.host, url.port) do |http|
+
    headers = prepared_headers
      sign_request
+
    headers['Accept'] = format
      assign_format(format)
+
    request = Net::HTTP::Get.new(request_uri(uri), headers)
      @request = Net::HTTP::Get.new(url.path, @headers)
+
    http_response = make_request request, uri
   
+
  end
       http.request(@request)
+
 
 +
  def delete(url_string)
 +
    uri = full_uri(url_string)
 +
     request = Net::HTTP::Delete.new(request_uri(uri), prepared_headers)
 +
    http_response = make_request request, uri
 +
  end
 +
 
 +
  def put(url_string, fields_hash)
 +
    uri = full_uri(url_string)
 +
    request = Net::HTTP::Put.new(request_uri(uri), prepared_headers)
 +
    request.set_form_data(fields_hash)
 +
    http_response = make_request request, uri
 +
  end
 +
 
 +
  def post(url_string, fields_hash)
 +
    uri = full_uri(url_string)
 +
    request = Net::HTTP::Post.new(request_uri(uri), prepared_headers)
 +
    request.set_form_data(fields_hash)
 +
    http_response = make_request request, uri
 +
  end
 +
 
 +
#
 +
# HTTP Request Helpers
 +
#
 +
  def make_request request, uri
 +
    response = Net::HTTP::start(uri.host, uri.portdo |http|
 +
       http.request request
 
     end
 
     end
 +
   
 +
    response
 
   end
 
   end
+
 
   def post(url_string, format, fields_hash)
+
   def full_uri url_string
     url = URI.parse('https://' + server_host + server_port + version + url_string)
+
     URI.parse('http://' + @server + @version_prefix + url_string)
 
+
  end
    sign_request
+
 
    assign_format(format)
+
  def request_uri uri
     @request = Net::HTTP::Post.new(url.path, @headers)
+
     request = uri.path
 
+
     if ! uri.query.nil?
     @request.set_form_data(fields_hash)
+
       request = request + '?' + uri.query
    @response = Net::HTTP::start(url.host, url.port) do |http|
 
       http.request(@request)
 
 
     end
 
     end
 +
    request
 
   end
 
   end
 
+
 
   def assign_format (format)
+
   def prepared_headers
     @headers['Accept'] = format
+
    headers = Hash.new
 +
    headers.merge! headers_auth_creds(@user_key, @secret_hash)
 +
     headers['Accept'] = xml_format
 +
    headers
 
   end
 
   end
+
 
   def sign_request
+
   def headers_auth_creds apiKey, secretKey
 
     userAgent = 'Ruby Test Client'
 
     userAgent = 'Ruby Test Client'
     timestamp = DateTime.now.new_offset.strftime('%Y%m%d%H%M%S00')
+
     timestamp = DateTime.now.strftime('%Y%m%d%H%M%S')
     apiKey = 'XXXXXXXXXXXXXXXXXXXX'
+
      
    secretKey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
 
 
 
     data_to_sign = apiKey + userAgent + timestamp + secretKey
 
     data_to_sign = apiKey + userAgent + timestamp + secretKey
+
   
     signature = Base64.encode64(Digest::SHA1.digest(data_to_sign))
+
     hash = Base64.encode64(Digest::SHA1.digest(data_to_sign))
+
    signature = apiKey + ":" + timestamp + ":" + hash
     @headers = Hash.new
+
   
    @headers['User-Agent'] = userAgent
+
     headers = Hash['User-Agent' => userAgent, 'X-Api-Signature' => signature]
    @headers['X-Api-Signature'] = apiKey + ":" + timestamp + ":" + signature
 
  end
 
 
  def server_host
 
    'api.emailsrvr.com'
 
  end
 
 
  def server_port
 
    '80'
 
  end
 
 
 
  def version
 
    '/v0'
 
 
   end
 
   end
 
end
 
end
 
</pre>
 
</pre>
 
  
 
=== C# ===
 
=== C# ===
Line 542: Line 750:
 
     client.Headers["User-Agent"] = userAgent;
 
     client.Headers["User-Agent"] = userAgent;
  
     var dateTime = DateTime.UtcNow.ToString("yyyyMMddHHmmssff");
+
     var dateTime = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
  
 
     var dataToSign = apiKey + userAgent + dateTime + secretKey;
 
     var dataToSign = apiKey + userAgent + dateTime + secretKey;

Latest revision as of 06:51, 7 February 2019

Recent Changes

09/01/10

New features:

  • Now Rackspace Email Mailboxes can be visible in Exchange Global Address List. And Exchange Mailboxes can be visible in Rackspace Email Company Directory.
  • Now Index Rackspace Email/Exchange Mailbox can filter mailboxes by "enabled" flag.
  • Added "lastLogin" to Rackspace Email/Exchange Mailbox Show.

08/01/10

New features:

  • Added Rackspace Email Mailbox Contact info. See here.
  • Added Create Login Token. See here.

06/20/10

New features:


06/11/10

New features:

  • Added Rackspace Email Mailbox Spam Settings/Blacklist/Safelist. See here.
  • Now Rackspace Email Mailbox can Show/Edit vacation message and email forwarding address. See here.
  • Added SharePoint Service Settings. See here.


Introduction

The Email & Apps Control Panel API provides most of the functions of the Control Panel through a REST-based web API. Whether it is adding a new customer account, adding mailboxes, or any other of the supported features the API allows your application to administer the changes regardless of your application's language or nature. For more information on RESTful web services refer to the following sites:

Paul James's Homepage: A RESTful Web service, an example

Wikipedia: Representational State Transfer - External Links


The API is accessible to all with access to Control Panel, including resellers, business customers, enterprise customers, and indirect customers. However, not all operations are available to non-resellers. See the Operations section for more details.

Operations

The following pages detail the operations that the API supports. The operations are grouped into sections based on the entity/object types that each operation interacts with. Non-resellers do not have access to all functions.

Resource Example URI Business User Access
Customer /customers/123456789 Create Login Token
DKIM /customers/123456789/domains/example.com/dkim/enable All
Domain /customers/123456789/domains/example.com Index, Show, Split Domain Routing, Archiving SSO Login URL, Domain Public Folders
Domain Spam Settings /customers/123456789/domains/example.com/spam/settings All
Rackspace Email Mailbox /customers/123456789/domains/example.com/rs/mailboxes/john.smith All
Rackspace Email Mailbox Spam Settings /customers/123456789/domains/example.com/rs/mailboxes/john.smith/spam All
Rackspace Email Alias /customers/123456789/domains/example.com/rs/mailboxes/john.smith/alias All
Exchange Mailbox /customers/123456789/domains/example.com/ex/mailboxes/john.smith All
Exchange Mailbox Spam Settings /customers/123456789/domains/example.com/ex/mailboxes/john.smith/spam All
Exchange Contact /customers/123456789/domains/example.com/ex/contacts/john.smith All
Exchange Distribution List /customers/123456789/domains/example.com/ex/distributionlists/group.name All
Exchange Resource Mailbox /customers/123456789/domains/example.com/ex/resources/conference.room All
SharePoint /customers/123456789/sharepoint/settings Show


The examples shown in the operation pages are written in Ruby and extensively use the helper functions shown in the Ruby Examples below.

Quick Start

What you need:

  • A Rackspace Email and Apps Control Panel admin account
  • A HTTP class library that supports TLS and the HTTP methods: GET, POST, PUT, DELETE.


Making your first API call, an Show Customer request:

  1. Obtain your API keys
    • Click on My Account at the top of the Control Panel web interface. Under the Administrators heading there will be an link for the API keys page.
  2. Set up your client's HTTP request
    • Set up your client to make calls to a URL beginning with https://api.emailsrvr.com/v0.
    • Populate the Accept, User-Agent and X-Api-Signature HTTP request headers correctly. This is explained in detail here.
  3. Make a GET request to /customers/me.
    • The complete URI will be https://api.emailsrvr.com/v0/customers/me. Use your HTTP library to retrieve the HTTP response code, 'x-error-message' HTTP response header and HTTP response body so that they may be displayed to help debug and determine success.

From here:

  • Learn about the operations you'll be implementing at the subpages here.

Accessing the API

Your application will need to make HTTP requests to remote servers. Most programming languages have this function provided in its class library. In addition to the common GET and POST HTTP methods, the library used will also need to support PUT and DELETE.

Calls without TLS (formerly SSL) will complete successfully but it is HIGHLY RECOMMENDED that TLS always be used. Interception of unencrypted communication will allow a third party to have complete access to all functions available via the API.

For some language libraries just using an URL with https:// will cause the library to use TLS. In some other libraries however some options specific to the library may have to be configured to utilize TLS.


All API calls should be directed to a URL in the following format:

https://api.emailsrvr.com/(version)/(resource)

Example:

https://api.emailsrvr.com/v0/customers/12345678/domains/customerbusiness.com


Versions

Supported Versions URL Version Documentation
v0 (current) https://api.emailsrvr.com/v0/ http://api-wiki.apps.rackspace.com/api-wiki/index.php/RestAPI


The API version number is a component of the URL that is used to access the API. For example, to access the root of the API, the URL is https://api.emailsrvr.com/v0/. Bug fixes and minor non-breaking changes will be made without changing the version number. When major features or breaking changes are introduced, the version number will be incremented. It is not yet determined how many versions are going to be supported at any one time.

Non-breaking Changes Breaking Changes
Adding new fields or attributes to form fields sent Changing or deleting any fields in form fields sent
Adding fields in returned data Changing or removing fields in returned data
Changing the URI of any resource


Authentication

To gain access to the API, your request must include a properly constructed X-Api-Signature HTTP header. Details on what to put in the header are below. To construct the header, you must have the following keys that that are generated from the Control Panel Web interface. The key generation page can be found by clicking 'My Account' at the top, then 'Generate API Keys' in the Administrators section.

Key Name Description Example
User Key A public key that corresponds to your admin id eGbq9/2hcZsRlr1JV1Pi
Secret Key A shared secret key QHOvchm/40czXhJ1OxfxK7jDHr3t


An unsuccessful authentication will result in a 403 HTTP code.


X-Api-Signature Header

Format is as follows: <User Key>:<Timestamp>:<SHA1 Hash>
Example: eGbq9/2hcZsRlr1JV1Pi:20010317143725:46VIwd66mOFGG8IkbgnLlXnfnkU=

Remember to include the colons between the data strings!


User Key:
This is the public key issued by the Control Panel browser interface.


Timestamp:
The format is YYYYMMDDHHmmss. All values besides year are zero-padded to two spaces. For example, March 08th 2001 at 2:37.25pm would be 20010308143725.

YYYY Four-digit year
MM Month
DD Day
HH Hour in 24h format
mm Minute
ss Second


SHA1 Hash:

A SHA1 (Secure Hash Algorithm) hash must be applied to a string with the following information:

<User Key><User Agent><Timestamp><Secret Key>

Note that the 'User Agent' must be the exact same as what is specified in the User-Agent HTTP header. Using the above example data, the string before hashing is:
eGbq9/2hcZsRlr1JV1PiRackspace Management Interface20010308143725QHOvchm/40czXhJ1OxfxK7jDHr3t

Resulting base-64 SHA1 Hash:
46VIwd66mOFGG8IkbgnLlXnfnkU=

Be sure to encode the binary hash, not the hex hash, into base-64. The resulting string should be 28 characters long.

Using the API

Requests

HTTP requests should be sent to the server with the correct URL, HTTP method, HTTP headers and form data (if needed). The URL specifies the resource, the HTTP method specifies what operation is done on the resource, and form data is used to specify the details of the resource when the resource is added or edited.

The URLs, corresponding HTTP methods, and necessary form data for the desired operations are detailed in the operation pages.


If you're getting the HTTP status code 417 see Handling HTTP code 417: Expectation failed

URL

The URLs are specifies the resource or resource collection. Objects are organized in a tree collection, starting with customers at the top, then domains, then domain objects next (such as mailboxes, contacts, and distribution lists) and so on. The URLs of the resources and collections accessible are found on the operation pages.

HTTP Method

It is the HTTP method that specifies what operation will be done on the resource. For example, to get the details of a mailbox a HTTP GET will be done on /customers/12345678/domains/example.com/ex/mailboxes/john.smith. If the mailbox does not exist, a HTTP POST to the same URL with the necessary form data will add the mailbox. Then, a HTTP PUT to the same URL will edit mailbox. And to delete the mailbox, an HTTP DELETE would be used.

The types of operations a certain method performs is outlined below.

HTTP Method Operations Response
GET Index - returns a list of the resources XML or JSON formatted data
Show - returns the details of the resource
POST Add - adds a new resource Response code and error message (if applicable) only
PUT Edit - changes the details of the resource
DELETE Delete - deletes the resource


HTTP Headers

All requests to the API must then include HTTP headers with the following information:

Header Name Description Example Header Value
Accept The requested content type (required for Index and Show actions). Fill this with either 'text/xml' or 'application/json'. See Response Formats text/xml
User-Agent An identifier you choose for your client software Rackspace Management Interface
X-Api-Signature An authentication string explained in detail here eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=

Form Data

When using Add and Edit operations, the details of the resource are sent to the API server via HTTP form data. Your HTTP library should include methods for sending form data along with an HTTP request. The library should by default send the data in the HTTP request body using the 'application/x-www-form-urlencoded' data format.

Index Filter/Search

The results of Index actions can be filtered/searched. The index URLs can take either one of the query strings: "?startswith=xx" or "?contains=xx," where "xx" is the key word. If the request specifies more than one of these two query strings, a 400 HTTP error will be returned. Different fields will be searched depending on the resource type, see below.

Note that "0-9" is a reserved key word for query string "startswith." It represents any result starting with numbers.

Index Actions Where the key word will be searched
Customer Customer name, account number, reference number
Domain Domain name
Mailbox Mailbox name, mailbox display name
Contact Contact display name, external email
Group Group name, group display name
Mobile Service Associated mailbox name, mailbox display name


Throttling

The server limits the number of requests allowed per user in a certain period of time. The number of requests made are logged per minute. Calls that were made correctly with a user's API key, but not completed for any reason, including those exceeding the throttle limit, are included in this count.

If a user is over the throttling limit then a 403 HTTP code will be returned with an "Exceeded request limits" message.


Operation Category Request Limit
GET 60 per minute
PUT, POST, DELETE 30 per minute
POST, PUT, DELETE on a domain 2 per minute
POST, DELETE on alternate domains 2 per minute
Enabling public folders for a domain 1 per 5 minutes


Examples

Index of Exchange Mailboxes:

Hypertext Transfer Protocol
    GET /v0/customers/12345678/domains/example.com/ex/mailboxes?size=100&offset=100 HTTP/1.1
    Host: api.emailsrvr.com
    User-Agent: Rackspace Management Interface
    X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
    Accept: text/xml

Adding New Exchange Mailbox:

Hypertext Transfer Protocol
    POST /v0/customers/12345678/domains/example.com/ex/mailboxes/john.smith HTTP/1.1
    Host: api.emailsrvr.com
    User-Agent: Rackspace Management Interface
    X-Api-Signature: eGbq9/2hcZsRlr1JV1Pi:20010317143725:HKUn0aajpSDx7qqGK3vqzn3FglI=
    Content-Length: 53
        [Content length: 53]
    Content-Type: application/x-www-form-urlencoded
 
Line-based text data: application/x-www-form-urlencoded
    size=2048&displayName=John%20Smith&password=abcABC123

Responses

HTTP Status Code

On a successfully executed request, a 200 HTTP Code is returned. If the request was unsuccessful however, an HTTP error code in the 400s or 500s will be returned.

HTTP Response Body

If the request is an Index or Show request, the request data will be returned in the format specified in the HTTP Body.

Formats

Requests for data (index and show requests) are returned with XML or JSON data based on what your application populates the HTTP Accept headers with.


For XML, populate the header with 'text/xml' (ex: Headers!["Accept"] = "text/xml"). The XML document returned will conform to a published XSD (XML Schema Document). There are many ways to parse the data in an XML document, but we have found that the XPath tree-style traversal has served our purposes. In any case, your application will likely need to use a class library for your chosen method.


For JSON, populate the header with 'application/json' (ex: Headers!["Accept"] = "application/json"). As with XML, a library will likely be needed to parse the data.

HTTP Headers

The only data returned in the header is the error message (if any).

Header Name Description Example Header Value
x-error-message The error message. See Errors. Missing required field: name

Errors

In the event of an error, the error message will be returned the HTTP header x-error-message and an HTTP Status Code in the 400s or 500s will be returned.

Note: Every language's HTTP library provides methods for retrieving HTTP response codes and response headers.

Below are some errors that are common to many operations. Each operation also has some specific errors which are outlined with the operation.

Description HTTP Response Code Sample Message
Format is invalid 400 When requesting an index or show on a resource the 'Accept' header should be either 'text/xml' or 'application/json'
Expectation Failed: See Handling HTTP code 417: Expectation failed 417 (none)
Customer account number is invalid 404 Invalid account number
Domain is not found 404 <domain name> not found
Mailbox is not found 404 Mailbox not found
Required form field is missing 400 Missing required field: <required field>
Required form field has null or empty string input 400 Required field <required field> cannot be empty
Integer form field has non-integer input 400 Invalid format for <field>, input must be an integer
Boolean form field has non-boolean input 400 Invalid format for <field>, input must be True or False
Form data has an unrecognized field 400 Unrecognized field: <field>
Entered invalid IP address 400 invalid ip address: 123

Paging

The results of Index actions are split into pages to lessen potentially high resource usage. The index URLs have a query string with parameters in the format "?size=xx&offset=xx." If a query parameter is omitted, the default value is used.

Query Parameter Default Maximum Notes
size 50 250 This is the number of elements per page.
offset 0 N/A This is the number of items to offset away from the first item in the list.
Example

A PHP Example of paging can be found here.

Examples

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.0
Date: Fri, 04 Dec 2009 19:08:11 GMT
Content-Length: 430

<?xml version="1.0" encoding="utf-8"?>
<domainList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:xml:domainList">
  <offset>0</offset>
  <size>50</size>
  <total>1</total>
  <domains>
    <domain>
      <name>customer.com</name>
      <accountNumber>123456</accountNumber>
      <serviceType>rsemail</serviceType>
    </domain>
  </domains>
</domainList>
HTTP/1.1 404 Not Found
Cache-Control: private
Server: Microsoft-IIS/7.0
x-error-message: Customer Not Found
Date: Fri, 04 Dec 2009 19:13:59 GMT
Content-Length: 0
HTTP/1.1 400 Bad Request
Cache-Control: private
Server: Microsoft-IIS/7.0
x-error-message: Missing required field: type
Date: Fri, 04 Dec 2009 19:17:29 GMT
Content-Length: 0


Examples

Ruby

This examples is written in Ruby. To make the examples shorter, helper methods have been written. These methods are part of a NetMethods module. The contents of the NetMethods module is listed below.

require  'server.rb'

server = Server.new

response = server.get  '/customers', server.xml_format

#fields = Hash['serviceType' =>  'exchange', 'exchangeMaxNumMailboxes' => '4']
#response =  server.post '/customers/me/domains/newdomain.com', fields

puts response.code
puts response['x-error-message']
puts response.body
require 'test/unit/assertions'
require 'net/http'
require 'date'
require 'date/format'
require 'digest/sha1'
require 'base64'
require 'time'

class Server
  include Test::Unit::Assertions
  
  def initialize(server='api.emailsrvr.com', version_prefix='/v0', user_key='xxxxxxxxxxxxxxxxxxxx', secret_hash='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
    @server = server
    @version_prefix = version_prefix
    @user_key = user_key
    @secret_hash = secret_hash
  end
  
# Response Type Enums

  def xml_format
    'text/xml'
  end
  
  def json_format
    'application/json'
  end

#
# HTTP Request Verbs
#  
  def get(url_string, format)
    uri = full_uri(url_string)
    headers = prepared_headers
    headers['Accept'] = format
    request = Net::HTTP::Get.new(request_uri(uri), headers)
    http_response = make_request request, uri
  end
  
  def delete(url_string)
    uri = full_uri(url_string)
    request = Net::HTTP::Delete.new(request_uri(uri), prepared_headers)
    http_response = make_request request, uri
  end
  
  def put(url_string, fields_hash)
    uri = full_uri(url_string)
    request = Net::HTTP::Put.new(request_uri(uri), prepared_headers)
    request.set_form_data(fields_hash)
    http_response = make_request request, uri
  end
  
  def post(url_string, fields_hash)
    uri = full_uri(url_string)
    request = Net::HTTP::Post.new(request_uri(uri), prepared_headers)
    request.set_form_data(fields_hash)
    http_response = make_request request, uri
  end
  
#
# HTTP Request Helpers
# 
  def make_request request, uri
    response = Net::HTTP::start(uri.host, uri.port)  do |http|
      http.request request
    end
    
    response
  end
  
  def full_uri url_string
    URI.parse('http://' + @server + @version_prefix + url_string)
  end
  
  def request_uri uri
    request = uri.path
    if ! uri.query.nil?
      request = request + '?' + uri.query
    end
    request
  end
  
  def prepared_headers
    headers = Hash.new
    headers.merge! headers_auth_creds(@user_key, @secret_hash)
    headers['Accept'] = xml_format
    headers
  end
  
  def headers_auth_creds apiKey, secretKey
    userAgent = 'Ruby Test Client'
    timestamp = DateTime.now.strftime('%Y%m%d%H%M%S')
    
    data_to_sign = apiKey + userAgent + timestamp + secretKey
    
    hash = Base64.encode64(Digest::SHA1.digest(data_to_sign))
    signature = apiKey + ":" + timestamp + ":" + hash
    
    headers = Hash['User-Agent' => userAgent, 'X-Api-Signature' => signature]
  end
end

C#

This examples is written in C#.

using System;
using System.Collections.Specialized;
using System.Security.Cryptography;
using System.Text;
using System.Net;

public class WebMethods
{
  private WebClientBase client;
  private string baseUrl;
  private string apiKey;
  private string secretKey;

  public WebMethods(WebClientBase client, string baseUrl, string apiKey, string secretKey)
  {
    this.client = client;
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
    this.secretKey = secretKey;
  }

  public virtual string Get(string url)
  {
    return MakeRemoteCall((client) =>
      {
        return client.DownloadString(baseUrl + url);
      },
      format);
  }

  public virtual string Post(string url, NameValueCollection data)
  {
    return MakeRemoteCall((client) =>
      {
        var bytes = client.UploadValues(baseUrl + url, data);
        return Encoding.UTF8.GetString(bytes);
      },
      format);
  }

  private void SignMessage()
  {
    var userAgent = "C# Client Library";
    client.Headers["User-Agent"] = userAgent;

    var dateTime = DateTime.UtcNow.ToString("yyyyMMddHHmmss");

    var dataToSign = apiKey + userAgent + dateTime + secretKey;
    var hash = SHA1.Create();
    var signedBytes = hash.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
    var signature = Convert.ToBase64String(signedBytes);

    client.Headers["X-Api-Signature"] = apiKey + ":" + dateTime + ":" + signature;
  }

  private void AssignFormat(string format)
  {
    client.Headers["Accept"] = format;
  }

  private string MakeRemoteCall(Func<WebClientBase, string> remoteCall, string format)
  {
    try
    {
      SignMessage();
      AssignFormat(format);
      return remoteCall.Invoke(client);
    }
    catch (WebException e)
    {
      throw new ApiException(e);
    }
  }
}


PHP

The PHP Example can be found here.