API Technical Details

We recommend that you use our Sailthru API libraries. These are debugged and in widespread use. But there may be situations where you need or want to write your own library, or otherwise directly access the API. This document explains the details.

Basic Rules

All API requests are either GET, POST, or DELETEs to paths on the host api.sailthru.com. It’s mandatory to send Sailthru HTTPS requests.

The URL will be https://api.sailthru.com/name, where name is the name of the call. For example, sendrequests are either a GET or POST to https://api.sailthru.com/send

All requests and responses must always be UTF-8 encoded.

The Sailthru API supports all versions of TLS, but does not support SSL, due to known security vulnerabilities with SSL.

API requests and responses in ISO-8859-1, not UTF-8, will result in an “Unable To Stream” error.

In REST style, a GET and a POST have different behaviors and often take different parameters. The documentation for each action type will explain these differences. Consistently, a GET is idempotent and will only return information to you – it will never make any changes or cause any action to be taken; a POST is not idempotent.

Parameters are passed either as part of the GET query string or as the POST body. This means your POSTs must be of the MIME content-type application/x-www-form-urlencoded. All parameters must be properly URL-encoded.

One shortcoming of URL parameters is that they do not preserve type data. For all API calls, you are allowed to pass a single parameter called jsoncontaining an object representation of all of your parameters. This is the recommended approach supported by most of the client libraries.


We use a simple shared-secret hash authentication mechanism. (For added security, you are strongly recommended to restrict the list of IPs that are allowed to access your API on your Settings page).

You have to start by knowing your API key and shared secret. You can get that information at the API Settings page.

Every request, whether GET or POST, must pass your API key as one of the parameters, as a parameter named api_key.

Every request must also generate a signature hash called sigaccording to the following rules:

  1. take the string values of every parameter, including api_key
  2. sort the values alphabetically, case-sensitively (i.e. ordered by Unicode code point)
  3. concatenate the sorted values, and prepend this string with your shared secret
  4. generate an MD5 hash of this string and use this as sig
  5. now generate your URL-encoded query string from your parameters plus sig

Example: Let’s suppose your API key is abcdef1234567890abcdef1234567890and your shared secret is 00001111222233334444555566667777. Let’s further suppose you’re doing an API call with the following parameters:

  • email=test@example.com
  • format=xml
  • vars[myvar]=TestValue
  • optout=0

Follow the steps:

  1. The string values of every parameter, including api_keyare: test@example.comxmlTestValue0, and abcdef1234567890abcdef1234567890.
  2. Sorting these values case-sensitive alphabetically, they are in this order: 0TestValueabcdef1234567890abcdef1234567890test@example.comxml
  3. Concatenate these sorted values and prepend the string with the shared secret and we get a signature string of000011112222333344445555666677770TestValueabcdef1234567890abcdef1234567890test@example.comxml
  4. Run md5() on that string and we get a signature hash of b0c1ba5e661d155a940da08ed240cfb9
  5. So our final query string looks like this: email=test@example.com&format=xml&vars[myvar]=TestValue&optout=0&api_key=abcdef1234567890abcdef1234567890&sig=b0c1ba5e661d155a940da08ed240cfb9

To see signature strings and hashing in action, try out some test API requests at the API test page. This page should give you all the information you need to debug.

The Most Common Mistake You Might Make While Authenticating

It’s a very common mistake when coding your own client to URL-encode at the wrong time. Do not URL-encode any of your parameters before generating the signature string, but do URL-encode before you send the HTTPS request. Depending on what HTTPS library you’re using, it may take care of URL-encoding for you, but if you have to generate your own query string, you need to do that as the last step. This problem often goes unnoticed until you attempt to pass a character that should be encoded, like =or &.

So for example, if you are trying to pass the value PB & J, you should be sorting and generating the md5() (doing steps 1-4 above) on the literal value PB & J. The ampersand should not be encoded. Then, after you’ve generated the sig hash, encode it to PB+%26+Jwhen building the query string.

Binary Parameter Values and Authentication

It is permitted to pass binary parameters, e.g. file upload names for the job API call. These binary parameters are **not** included in the signature hash.

Response Format

For most requests, we support three response formats: simple XML, JSON, and serialized PHP.

If you are coding in PHP, we recommend serialized PHP. Otherwise, we generally recommend JSON. For legacy reasons, though, XML is the default.

You can specify which response format by passing a formatparameter and using one of the following values: xmljson, or php.

The response will be a structure with fields that will vary depending on the call you are making. The responses are individually documented for each call.

If we encounter an error, we will return a structure with two fields: error, which will contain a numeric error code, and errormsg, which will return a message. The errormsgis usually technical in nature and most likely not something you will want to expose to an end user.

If you’re using JSON or PHP, the response structure will be pretty natural: a JSON object or a PHP associative array. If you’re using XML, we convert the JSON object to XML according to consistent rules:

  • key/value pairs become <key>value</key>
  • numeric arrays become <item>element0</item><item>element1</item><item>element2</item>… etc
  • there will be an opening and closing element

So, for instance, a JSON response that read:

{ foo: 'bar',

  baz: 2,
  baps: ['a', 'b', 'c']


becomes XML




Good Luck!

If you are having troubles, feel free to contact us. And if you happen to write a client for a language we don’t currently have a client for, please consider donating it back to the larger Sailthru community.