Table of Contents

    API

    Mock Server

    Use this URL to access a mockup of the API server. Your traffic will be recorded and compared to the documentation. You'll find your traffic analysis in the inspector or directly here in the documentation, right next to each resource.

Message Bus v5 REST API

Status & Error Codes

This section defines the status & error codes used by Message Bus.

Success

200 | Ok                 | Success, payload accompanies response if appropriate.
201 | Created            | Success, the requested resource was created.
202 | Accepted           | Success, but results are not immediately available.
204 | No Content         | Success, no response payload.
207 | Partial Success    | Used for mult-part requests where some items may result in different statuses.

Failure

400 | Invalid Request    | One or more parameters were invalid.
401 | Unauthorized       | Unauthorized; missing API key.
402 | Request Failed     | Request failed; insufficient permission.
403 | Forbidden          | Request rejected; invalid API key.
404 | Not Found          | Some object in the request was invalid.
405 | UNUSED             | Method not allowed.
406 | Not Acceptable     | Not acceptable; use application/json; charset=utf-8
408 | UNUSED             | Request Timeout.
409 | UNUSED             | Conflict.
410 | UNUSED             | Gone.
413 | Request Too Large  | Request too large; send <= 100 messages per batch.
415 | Request Unparsable | Request unparsable; check POST JSON.
422 | Request Rejected   | Request rejected; could not send message to recipient.

Error

500 | Internal Server Error  | Internal service error, ALL HELL IS BREAKING LOOSE! AAAAAAAAHHHHHH!!!!!
501 | Not Implemented        | Method or service not yet implemented.
503 | Service Unavailable
507 | UNUSED                 | Insufficient Storage 

Message Bus Status Codes

0    | Success         | Whatever it was, it's all good.
1001 | General Failure | Watch out for Lieutenant Yerfucked.
1002 | Invalid 'To' email address
1003 | Invalid 'From' email address
1004 | Missing Subject
1005 | Missing Body
1006 | Invalid Message-ID header
1010 | Invalid SessionKey
1012 | Invalid Return-Path

Message Bus Bounce Codes

0    | UNDETERMINED - (ie. Recipient Reply or not a bounce)
10   | HARD BOUNCE - (ie. User Unknown)
20   | SOFT BOUNCE - General
21   | SOFT BOUNCE - DNS Failure
22   | SOFT BOUNCE - Mailbox Full
23   | SOFT BOUNCE - Message Too Large
30   | BOUNCE - no email address
40   | GENERAL BOUNCE
50   | MAIL BLOCK - General
51   | MAIL BLOCK - Known Spammer
52   | MAIL BLOCK - Spam Detected
53   | MAIL BLOCK - Attachment Detected
54   | MAIL BLOCK - Relay Denied
60   | AUTO REPLY - (ie. Out Of Office)
70   | TRANSIENT BOUNCE
80   | SUBSCRIBE Request
90   | UNSUBSCRIBE/REMOVE Request
100  | CHALLENGE-RESPONSE
1000 | SOFT BOUNCE - Bounce due to retry expiry
1010 | HARD BOUNCE - Message rejected with SMTP 5yz
1011 | HARD BOUNCE - Message was rejected by ISP policy, address will not be suppressed

Message Bus Block Codes

0    | Global
1    | Channel

Version

Returns the current version of the API server. Note that this is the only API that doesn't have a version in the path.

IMPLEMENTATION NOTE

Apiary forces the v5 prefix onto everything in this blueprint, but it MUST NOT be prepended to the version route.

GET

/v5/version

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "API Version Lookup",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "APIName"       : "api",
    "APIVersion"    : "version string"
}

Channel and Session API

Purpose

Channels & sessions provide traffic segmentation within a user's account.

  • Channels & Sessions control how messages are sent, map to specific IPs, and configure tracking features on those messages.
  • Sessions make it easy to group similar messages together when looking at stats/feedback or viewing send performance in the HUD.

The Channels API allows users to:

  1. enumerate and modify but not create channels
  2. create, enumerate, and modify sessions

GET

/v5/channels

Get Channel List

List all the active channels in the account. 'active' means 'usable'

Returns

count                 | int    | number of channels returned

CHANNELS
    channelName       | string | friendly name of channel
    channelKey        | guid   |
    defaultSessionKey | guid   | default sessionKey on this channel
    isDefault         | bool   | true, if this is the account's default channel

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Ok",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "count"         : 1,
    "channels" :
    [
        {
            "channelName"       : "Friendly Channel Name",
            "channelKey"        : "0000000000ABCDEF0123456789ABCDEF",
            "defaultSessionKey" : "1111111111ABCDEF0123456789ABCDEF",
            "isDefault"         : true
        }
    ]
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/channel/{channelKey}

Get Channel Configuration

Returns current configuration values for the specified channel

Returns

CONFIGURATION
    channelName                | string | friendly name of the channel
    isDefault                  | bool   | whether the channel is the default
    defaultSessionKey          | guid   | default session's key for this channel
    addUnsubscribe             | bool   | enable unsub; honor the UNSUBSCRIBE_URL link token & insert a list-unsubscribe header
    unsubscribeCustomDomain    | string | custom domain for unsub link
    addOpenRate                | bool   | enable open tracking
    openRateCustomDomain       | string | custom domain for open beacon url
    addClickDetection          | bool   | enable link click tracking
    clickDetectionCustomDomain | string | custom domain for click tracking
    exceptionList              | array  | list blocklist exceptions, can be a specific mailbox or a wildcard## Returns

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Ok",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "configuration" :
    {
        "isDefault"                  : false,
        "defaultSessionKey"          : "1111111111ABCDEF0123456789ABCDEF",
        "channelName"                : "friendly name",
        "addUnsubscribe"             : true,
        "unsubscribeCustomDomain"    : "services.messagebus.com",
        "addOpenRate"                : true,
        "openRateCustomDomain"       : "services.messagebus.com",
        "addClickDetection"          : true,
        "clickDetectionCustomDomain" : "services.messagebus.com",
        "exceptionList"              :
        [
            "*@mydomain.net",
            "bob@hotmail.com"
        ]        
    }
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; channel does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

PUT

/v5/channel/{channelKey}

Set Channel Configuration

Sets configuration values. Only operates on those specified in the request body.

Params

Use same key/value pairs as for GET /channel/{guid}

Returns

Completion status

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Configuration updated.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; channel does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/channel/{channelKey}/sessions

Get Session List

Returns the sessions for the specified channel

Returns

count           | int    | the number of sessions returned

SESSIONS
    sessionKey  | guid   | 
    sessionName | string |
    isDefault   | bool   | true if this is the channel's default session

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Ok",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "count"         : 1,
    "sessions" :
    [
        {
            "sessionName"       : "Friendly Session Name",
            "sessionKey"        : "1111111111ABCDEF0123456789ABCDEF",
            "isDefault"         : false
        }
    ]
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; channel does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

POST

/v5/channel/{channelKey}/sessions

Create Session

Creates a new session with the specified options

Params

sessionName | string | friendly name for the new session

Returns

sessionKey | guid | unique identifier for the new session

Response

201 (Created)
{
    "statusCode"        : 201,
    "statusMessage"     : "Session created.",
    "statusTime"        : "1971-01-01T00:00:00.000Z",
    "sessionName"       : "my new session",
    "sessionKey"        : "1111111111ABCDEF0123456789ABCDEF"
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; channel does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

PUT

/v5/channel/{channelKey}/session/{sessionKey}

Modify Session

Allows the user to modify session configuration, currently limited to renaming the session

Params

sessionName | string | new friendly name

Returns

sessionName | string | echoes back the session name

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Configuration updated.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "sessionName"   : "new session name"
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; channel or session does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Send API

Purpose

Send non-templated messages.

Open Issues

  1. returnPath parameter - in or out? Pmidge prefers "out" because this should be an account/channel setting, there's only pain and suffering in a world where customers can change this.
  2. do we really need all those 4yz response codes? have we ever returned 415 or 422? Re:2 We should never return 415 for debugged clients but if you test via curl and send in bad JSON you will get it as the JSON parse exception

POST

/v5/messages/send

Send Messages

Send a message the old-fashioned way, without templates.

Params

sessionKey    | guid   | the session guid to use when sending this message
toEmail       | string | the recipient's RFC5322 email address
toName        | string | the recipient's friendly name
fromEmail     | string | the sender's RFC5322 email address
fromName      | string | the sender's friendly name
returnPath    | string | the sender's RFC5321 bounce address, also called the "envelope sender"
subject       | string | the message subject line
plaintextBody | string | the plain text content of the message, shown to mail programs that cannot render HTML
htmlBody      | string | the html version of the message contents, shown to 99.999% of recipients
customHeaders | hash   | custom headers to insert into the message

Returns

statusCode        | int    | 202 => All messages accepted; 207 => Some messages were not accepted
successCount      | int    | count of messages accepted for delivery
failureCount      | int    | count of messages not accepted for delivery

RESULTS
    toEmail       | string | the recipient email address for the message represented by this status
    messageId     | guid   | the message-id generated for this recipient
    messageStatus | int    | the api status code (e.g. 1yza) associated with this message

Response

202 (Accepted)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 202,
    "statusMessage" : "Messages accepted; delivery pending.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "successCount"  : 1,
    "failureCount"  : 0,
    "results" :
    [
        {
            "toEmail"       : "bob@hotmail.com",
            "messageId"     : "AAAABBBBCCCCDDDDEEEEFFFF00001111",
            "messageStatus" : 0
        }
    ]
}

Response

207
content-type: application/json; charset=utf-8
{
    "statusCode"    : 207,
    "statusMessage" : "Not all messages were accepted; see messageStatus for more details.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "successCount"  : 1,
    "failureCount"  : 1,
    "results" :
    [
        {
            "toEmail"       : "bob@hotmail.com",
            "messageId"     : "AAAABBBBCCCCDDDDEEEEFFFF00001111",
            "messageStatus" : 0
        },
        {
            "toEmail"       : "jane@gmail.com",
            "messageId"     : "",
            "messageStatus" : 1004
        }        
    ]
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

406 (Not Acceptable)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 406,
    "statusMessage" : "Not acceptable; use application/json; charset=utf-8.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

413 (Request Entity Too Large)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 413,
    "statusMessage" : "Request too large; send <= 100 messages per batch.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

415 (Unsupported Media Type)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 415,
    "statusMessage" : "Request unparsable; check POST JSON.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Template API

Purpose

Allows customers to create content templates and do mail-merge-style sending.

POST

/v5/templates

Create Template

Uploads a template to your account and returns a template key on success.

Params

sessionKey    | guid   | the session guid to use when sending this message
toEmail       | string | the recipient's RFC5322 email address
toName        | string | the recipient's friendly name
fromEmail     | string | the sender's RFC5322 email address
fromName      | string | the sender's friendly name
returnPath    | string | the sender's RFC5321 bounce address, also called the "envelope sender"
subject       | string | the message subject line
plaintextBody | string | the plain text content of the message, shown to mail programs that cannot render HTML
htmlBody      | string | the html version of the message contents, shown to 99.999% of recipients
customHeaders | hash   | custom headers to insert into the message

Returns

templateKey   | guid | template's unique identifier

Response

201 (Created)
content-type: application/json; charset=utf-8
{ 
  "statusCode"    : 201,
  "statusMessage" : "Template saved",
  "statusTime"    : "1971-01-01T00:00:00.000Z",
  "templateKey"   : "0000aaaa-bbbb-cccc-dddd-111122223335"
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

406 (Not Acceptable)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 406,
    "statusMessage" : "Not acceptable; use application/json; charset=utf-8.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

415 (Unsupported Media Type)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 415,
    "statusMessage" : "Request unparsable; check POST JSON.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

PUT

/v5/template/{templateKey}

Update Template

Updates an existing template. The entire template needs to be re-submitted, just like a template create.

Params

sessionKey    | guid   | the session guid to use when sending this message
toEmail       | string | the recipient's RFC5322 email address
toName        | string | the recipient's friendly name
fromEmail     | string | the sender's RFC5322 email address
fromName      | string | the sender's friendly name
returnPath    | string | the sender's RFC5321 bounce address, also called the "envelope sender"
subject       | string | the message subject line
plaintextBody | string | the plain text content of the message, shown to mail programs that cannot render HTML
htmlBody      | string | the html version of the message contents, shown to 99.999% of recipients
customHeaders | hash   | custom headers to insert into the message

Returns

templateKey | guid | template's unique identifier

Response

201 (Created)
content-type: application/json; charset=utf-8
{ 
  "statusCode"    : 201,
  "statusMessage" : "Template saved",
  "statusTime"    : "1971-01-01T00:00:00.000Z",
  "templateKey"   : "0000aaaa-bbbb-cccc-dddd-111122223335"
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

DELETE

/v5/template/{templateKey}

Delete a Template

Given a template key, delete it. Takes up to 5 minutes for caches to be cleared.

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Template deleted.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; template key does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/templates

List Templates

Fetches a list of all templates associated with a given account. Can be used to find the key for a template you want to download.

Returns

count                | int      | the number of templates in the account

TEMPLATES
    templateKey      | guid     | the template's unique id
    modificationTime | datetime | when the template was created
    size             | int      | size of the template in bytes

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Ok",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "count"         : 3,   
    "templates"     :
    [
        {
            "templateKey"      : "0000aaaa-bbbb-cccc-dddd-111122223333",
            "modificationTime" : "1971-01-01T00:00:00.000Z",
            "size"             : 51778
        },
        {
            "templateKey"      : "0000aaaa-bbbb-cccc-dddd-111122223334",
            "modificationTime" : "1971-01-01T00:00:00.000Z",
            "size"             : 52416
        },
        {
            "templateKey"      : "0000aaaa-bbbb-cccc-dddd-111122223335",
            "modificationTime" : "1971-01-01T00:00:00.000Z",
            "size"             : 52416
        }
    ]
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/template/{templateKey}

Get Template

Given a template key, allows you to fetch a previously-created template.

Returns

template | object | contents of the requested template

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Ok",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "template" :
    {
        "sessionKey"    : "DEFAULT",
        "toName"        : "{{customer_name}}",
        "toEmail"       : "{{customer_email}}",
        "fromName"      : "Billing Department",
        "fromEmail"     : "billing@example.com",
        "returnPath"    : "bounces@bounces.example.com",
        "subject"       : "Bill Due: {{service_name}}",
        "plaintextBody" : "no plaintext provided.",
        "htmlBody"      : "{{{body}}}",
        "customHeaders" :
        {
            "x-custom-header" : "{{header_value}}"
        }
    }
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; template key does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

POST

/v5/templates/send

Send Template

Sends email using a template key and merge data. Sends up to 25 messages at a time, response data matches /messages/send

Params

templateKey | guid   | unique id of the template to use for the send
messages    | object | OPTIONAL; array of message data, composition dependent on merge fields in template

Response

202 (Accepted)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 202,
    "statusMessage" : "Messages accepted; delivery pending.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "successCount"  : 1,
    "failureCount"  : 0,
    "results" :
    [
        {
            "toEmail"       : "bob@hotmail.com",
            "messageId"     : "AAAABBBBCCCCDDDDEEEEFFFF00001111",
            "messageStatus" : 0
        }
    ]
}

Response

207
content-type: application/json; charset=utf-8
{
    "statusCode"    : 207,
    "statusMessage" : "Not all messages were accepted; see messageStatus for more details.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "successCount"  : 1,
    "failureCount"  : 1,
    "results" :
    [
        {
            "toEmail"       : "bob@hotmail.com",
            "messageId"     : "AAAABBBBCCCCDDDDEEEEFFFF00001111",
            "messageStatus" : 0
        },
        {
            "toEmail"       : "jane@gmail.com",
            "messageId"     : "",
            "messageStatus" : 1004
        }        
    ]
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

406 (Not Acceptable)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 406,
    "statusMessage" : "Not acceptable; use application/json; charset=utf-8.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

413 (Request Entity Too Large)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 413,
    "statusMessage" : "Request too large; send <= 25 messages per batch.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

415 (Unsupported Media Type)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 415,
    "statusMessage" : "Request unparsable; check POST JSON.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

422
content-type: application/json; charset=utf-8
{
    "statusCode"    : 422,
    "statusMessage" : "Request rejected; could not send message to recipient.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Report API

Purpose

The Report API replaces the v4 Feedback & Stats API with a generalized job-based reporting infrastructure that doesn't require require the customer to block synchronously while the query is running. A request-check-retrieve cycle is used where the customer is given a report ID, they loop and check it for completion, and retrieve it when ready.

The API remains read-only, and events occurring within a specific date range may be retrieved from the entire account, a specific channel, or a single session.

Date Ranges

  1. A stats report can span a maximum of 90 days and cannot query data older than 90 days from the present time.
  2. A feedback report can span a maximum of 7 days and cannot query data older than 90 days from the present time.

How Dates are Interpreted

Dates are supplied using the startDate and endDate parameters on a query string or POST/PUT body. We only accept YYYY-MM-DDThh:mm:ss.sZ or YYYY-MM-DD and the values are interpreted as [startDate, endDate). startDate is always rounded down to the nearest hour, endDate rounded up. If no date range is supplied, the API will use the range now - 24hrs.

Report quotas

  1. Stats and blocklist reports have a daily quota of 500 reports per day.
  2. Feedback reports have a daily quota of 150 reports per day.

POST

/v5/reports

Request Report

Params

Parameter  | Type     | Supported by reportType    | Notes    
reportType | string   | stats, feedback, blocklist | REQUIRED 
format     | string   | stats, feedback, blocklist | OPTIONAL get data back as JSON* or CSV. DEFAULT: JSON
channelKey | guid     | stats, feedback, blocklist | OPTIONAL used to scope from account down to a single channel.
startDate  | datetime | stats, feedback            | OPTIONAL startDate of the query.
endDate    | datetime | stats, feedback            | OPTIONAL endDate of the query.
sessionKey | guid     | stats, feedback            | OPTIONAL used to scope from channel to a single session.
scope      | string   | feedback                   | OPTIONAL bounces, unsubscribes, complaints, clicks, opens, blocks. DEFAULT: bounces.

* JSON responses are newline delimited rows of JSON data

Returns

reportKey            | guid   | unique identifier for the report job that will eventually deliver the requested information
reportStatus         | string | state of the requested report, will always be "created" at this stage
reportQuota          | int    | the calling account daily report quota
reportQuotaRemaining | int    | the number of reports left in the daily quota

Response

201 (Created)
content-type: application/json; charset=utf-8
{
    "statusCode"           : 201,
    "statusMessage"        : "Report request received.",
    "statusTime"           : "1971-01-01T00:00:00.000Z",
    "reportKey"            : "FOODFOODFOODFOODFOODFOODFOODFOOD",
    "reportStatus"         : "created",
    "reportQuota"          : 500,
    "reportQuotaRemaining" : 499
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

402 (Payment Required)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 402,
    "statusMessage" : "Quota exceeded; try again later.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; report type invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

415 (Unsupported Media Type)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 415,
    "statusMessage" : "Request unparsable; check POST JSON.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/report/{reportKey}/status

Get Report Status

Check to see if a report is still running or has a final disposition.

Returns

statusCode   | int    | 200  | 200     | 200    | 402
reportStatus | string | done | running | nodata | failed

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Report has completed.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "reportStatus"  : "done"
}

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Report is still running.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "reportStatus"  : "running"
}

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 200,
    "statusMessage" : "Report contains no data.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "reportStatus"  : "nodata"
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

402 (Payment Required)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 402,
    "statusMessage" : "Report generation failed.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "reportStatus"  : "failed"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; reportKey invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/report/{reportKey}

Retrieve Report Data

Fetch a report that's in the "done" state.

This API returns reports in CSV and JSON format depending on the parameters supplied during report submission.

Returns

Note: For stats & feedback responses the only status given is the HTTP response code. There is no additional status in the payload.

HTTP Response Codes

200 | reportKey maps to a completed report that generated data, which is included in the response body
204 | reportKey maps to a completed report that generated no data
401 | missing or invalid API key
404 | reportKey is invalid

Streaming JSON Format (example)

{ ... }\n
{ ... }\n
{ ... }\n

Streaming CSV Format (example)

col1_label,col2_label,col3_label,...\r\n
f1,f2,f3,...\r\n    

Stats Reports

channelKey                | guid | channel unique identifier
sessionKey                | guid | session unique identifier
STATS
    complaintCount        | int  | count of complaints received
    unsubscribeCount      | int  | count of unsubscribes received
    clickCount            | int  | sum of all clicks received
    uniqueClickCount      | int  | count of unique clicks received
    openCount             | int  | sum of all opens received
    uniqueOpenCount       | int  | count of unique opens received
EMAIL
    messageCount          | int  | count of messages for which we generated a message-id
    errorCount            | int  | count of messages for which we DID NOT generate a message-id
    sentCount             | int  | count of messages resulting in SMTP 2yz
    expireCount           | int  | count of messages resulting in SMTP 4yz after retry period/count expires
    hardBounceCount       | int  | count of messages resulting in SMTP 5yz + bounceCode: 10
    softBounceCount       | int  | count of messages rejected AFTER delivery (NDR, C-R, OOF, etc.), not including messages accounted for in hardBounceCount
FILTER
    rcptBadMailboxCount   | int  | count of messages rejected* by platform bad mailbox list
    rcptChannelBlockCount | int  | count of messages rejected** by channel-level blocks

* resulting from hard bounces, or soft bounces with subcode:10

** resulting from unsubscribes or complaints

Feedback Reports

ALL REPORTS
type       | string | type of event; bounce, complaint, unsub, click, open, block
channelKey | guid   | channel unique identifier
sessionKey | guid   | session unique identifier

BOUNCE
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that bounced
    bounceCode | int      | type of bounce (see table at top of doc)
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

COMPLAINT
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that complained
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

UNSUB
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that complained
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

OPEN
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that complained
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

CLICK
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that complained
    trackingId | string   | the value of the "mbTrackingId" query string parameter
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

BLOCK
    messageId  | guid     | the message-id header from the original message
    email      | string   | the email address that was blocked
    blockCode  | int      | type of block (channel or global, see top of doc)
    eventTime  | datetime | time the event occurred
    sendTime   | datetime | time the message associated with this event occurred

Blocklist Reports

channelKey | guid     | channel unique identifier
email      | string   | the email address that was blocked
reason     | string   | the reason the address is blocked (e.g. complaint, unsub, etc.)

Response

200 (OK)
content-type: text/csv; charset=utf-8
channelKey,sessionKey,complaintCount,unsubscribeCount,...
0000000000ABCDEF0123456789ABCDEF,1111111111ABCDEF0123456789ABCDEF,0,0,...

Response

200 (OK)
content-type: text/csv; charset=utf-8
type,channelKey,sessionKey,email,bounceCode,eventTime,...
bounce,0000000000ABCDEF0123456789ABCDEF,1111111111ABCDEF0123456789ABCDEF,bob@hotmail.com,1000,1971-01-01T23:45:00.000Z,...

Response

200 (OK)
content-type: application/json; charset=utf-8
{
    "type"       : "bounce",
    "channelKey" : "0000000000ABCDEF0123456789ABCDEF",
    "sessionKey" : "1111111111ABCDEF0123456789ABCDEF",
    "email"      : "bob@hotmail.com",
    "bounceCode" : 1000,
    "eventTime"  : "1971-01-01T23:45:00.000Z",
    "sendTime"   : "1971-01-01T00:00:00.000Z"
}\n

Response

204 (No Content)

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; invalid report key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Webhooks

Webhooks are HTTP endpoints managed by a Message Bus customer that are called when an event they're interested in has occurred. Our API provides a mechanism to create & manage webhook registrations.

Event Groups

message   - events related to message-level activity
link      - link tracking events
recipient - events related to recipient-driven feedback

Event Payload

{
    eventType: [event namespace & type],
    count: [number of events in this call],
    events:
    [
        ...
    ]
}

Event Types & Data

                      | messageId | recipient | subject | channel/session | eventTime | subCode | nextAttempt | flightTime | attempts | url | trackingId | location | device | smtpLog |
      message.attempt |     X     |     X     |    X    |        X        |     X     |         |             |            |          |     |            |          |        |         |
       message.accept |     X     |     X     |    X    |        X        |     X     |         |             |      X     |     X    |     |            |          |        |    X    |
       message.bounce |     X     |     X     |    X    |        X        |     X     |    X    |             |            |          |     |            |          |        |    X    |
     message.deferral |     X     |     X     |    X    |        X        |     X     |         |      X      |            |     X    |     |            |          |        |    X    |
         message.open |     X     |     X     |    X    |        X        |     X     |         |             |            |          |     |            |     X    |   X    |         |
           link.click |     X     |     X     |    X    |        X        |     X     |         |             |            |          |  X  |      X     |     X    |   X    |         |
recipient.unsubscribe |     X     |     X     |    X    |        X        |     X     |         |             |            |          |     |            |     X    |   X    |         |
  recipient.complaint |     X     |     X     |    X    |        X        |     X     |         |             |            |          |     |            |          |        |         |
      recipient.block |     X     |     X     |    X    |        X        |     X     |         |             |            |          |     |            |          |        |         |

Event Data

messageId   | guid     | the unique message-id assigned to the message when we accepted it for delivery
recipient   | string   | the message's recipient address
subject     | string   | the subject line
chan/sess   | guid     | the channel & session keys used to transmit the message
eventTime   | datetime | the time the event was captured by Message Bus
subCode     | int      | a bounce code used to specifically identify why a message bounced
nextAttempt | datetime | for deferred messages, the approximate time we will make the next delivery attempt
flightTime  | int      | total time it took to deliver the message in milliseconds
attempts    | int      | the number of attempts it took for us to deliver the message
url         | string   | the unencoded URL a user was redirected to when clicking a tracked link
trackingId  | int      | the value specified in a tracked URL's mbTrackingId field
smtpLog     | string   | the raw SMTP response returned from the recipient domain

LOCATION - contains geograpic data associated with the client IP address generating the event
    latitude  | float    | client latitude
    longitude | float    | client longitude
    city      | string   | client city name
    region    | string   | client region code (e.g. two-letter state abbreviation in the US)
    country   | string   | client country code (e.g. two-letter country code)

NOT YET IMPLEMENTED
    device    | TBD | the type of device (either mobile, table, or desktop) where the message was received

Calling Semantics

We cannot make any assumptions about the availability or performance of the webhook we're calling. We consider an event successfully delivered when our POST request receives an HTTP 2yz-level response. If we receive a response other than HTTP 2yz, we will retry for 24 hours. If we're unable to deliver the event after 24 hours we will discard it.

GET

/v5/webhooks

List all webhooks

Retrieve a list of all webhooks.

Returns

An array of webhook configurations.

WEBHOOKS
    enabled    | bool   | is the webhook on or off?
    uri        | string | the customer-supplied HTTP endpoint called for the webhook
    webhookKey | guid   | the webhook's unique ID
    eventType  | string | the event this webhook services
    channelKey | guid   | the channel this webhook listens on

    BATCHING
        batchingEnabled  | bool | is batch operation enabled?
        batchTimeSeconds | int  | how long a batch lives before being submitted, if it doesn't exceet the size constraint
        maxBatchSize     | int  | how large a batch can get before it is submitted

Response

200 (OK)
Content-Type: application/json
{
    "webhooks": [
        {
            "batching": {
                "batchingEnabled": true,
                "batchTimeSeconds": 30,
                "maxBatchSize": 500
            },
            "channelKey": "57d60456-df68-4c53-9f89-5454d66a1788",
            "dateCreated": "2013-11-13T03:16:42Z",
            "enabled": true,
            "eventType": "message.attempt",
            "lastUpdated": "2013-11-13T03:16:42Z",
            "uri": "http://www.account1Channel1.com/message.attempt",
            "webhookKey": "43cc20c4-9f89-4799-8b7f-1f32dce39801"
        },
        {
            "batching": {
                "batchingEnabled": true,
                "batchTimeSeconds": 1,
                "maxBatchSize": 10
            },
            "dateCreated": "2013-11-13T03:16:42Z",
            "enabled": true,
            "eventType": "message.accept",
            "lastUpdated": "2013-11-13T03:16:42Z",
            "uri": "http://www.account1Channel1.com/message.accept",
            "webhookKey": "c9405843-68c2-46e1-b484-ef8d5e6bddc1"
        },
        {
            "batching": {
                "batchingEnabled": true,
                "batchTimeSeconds": 1,
                "maxBatchSize": 10
            },
            "channelKey": "57d60456-df68-4c53-9f89-5454d66a1788",
            "dateCreated": "2013-11-13T03:16:42Z",
            "enabled": true,
            "eventType": "message.accept",
            "lastUpdated": "2013-11-13T03:16:42Z",
            "uri": "http://www.account1Channel1.com/message.accept",
            "webhookKey": "d23def01-abbb-43a9-9344-f9e53e237eb9"
        }
    ],
    "statusTime": "2013-11-13T04:06:54Z",
    "statusCode": 200,
    "statusMessage": "OK"
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

200 (OK)
Content-Type: application/json
{
    "webhooks": [],
    "statusTime": "2013-11-13T04:06:54Z",
    "statusCode": 200,
    "statusMessage": "OK"
}

POST

/v5/webhooks

Create a webhook

Allows the caller to create a webhook for a specific event at the account or channel level.

Params

enabled    | bool     | OPTIONAL turns the webhook on or off. DEFAULT: true
uri        | string   | REQUIRED the customer-implemented HTTP endpoint that will receive POST data
eventType  | string   | REQUIRED see "event types & data"
channelKey | guid     | OPTIONAL scopes operation to a single channel, defaults to account level.

BATCHING - OPTIONAL object containing batch configuration options
    batchingEnabled   | bool | turns batch operation on or off
    batchTimeSeconds  | int  | OPTIONAL how long a batch lives before being submitted, if it doesn't exceet the size constraint. DEFAULT: 30 seconds
    maxBatchSize      | int  | OPTIONAL how large a batch can get before it is submitted. DEFAULT: 500 events

Returns

webhookKey | guid | unique identifier for the web hook.

Response

201 (Created)
Content-Type: application/json
{
    "statusCode"    : 201,
    "statusMessage" : "Webhook created.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
    "webhookKey"    : "FOODFOODFOODFOODFOODFOODFOODFOOD",
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

403 (Forbidden)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 403,
    "statusMessage" : "Unauthorized; insufficient permission.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

GET

/v5/webhook/{webhookKey}

Get a specific Webhook

Retrieve the configuration information for a specific webhook. Assumes the user has stored a list of webhookKeys or previously enumerated them using GET /v5/webhooks.

Returns

Webhook config data. See GET /v5/webhooks.

Response

200 (OK)
Content-Type: application/json
{
    "webhook": {
        "batching": {
            "batchingEnabled": true,
            "batchTimeSeconds": 30,
            "maxBatchSize": 500
        },
        "channelKey": "57d60456-df68-4c53-9f89-5454d66a1788",
        "dateCreated": "2013-11-13T03:16:42Z",
        "enabled": true,
        "eventType": "message.attempt",
        "lastUpdated": "2013-11-13T03:16:42Z",
        "uri": "http://www.account1Channel1.com/message.attempt",
        "webhookKey": "43cc20c4-9f89-4799-8b7f-1f32dce39801"
    },
    "statusTime": "2013-11-13T04:36:27Z",
    "statusCode": 200,
    "statusMessage": "OK"
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; webhook does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

PUT

/v5/webhook/{webhookKey}

Modify a webhook

Params

Use same key/value pairs as for GET /webhook/{webhookKey}, plus default

Returns

Completion status.

Response

200 (OK)
Content-Type: application/json
{
    "statusCode"    : 200,
    "statusMessage" : "Webhook updated.",
    "statusTime"    : "1971-01-01T00:00:00.000Z",
}

Response

400 (Bad Request)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 400,
    "statusMessage" : "One or more parameters were invalid.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"    
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; webhook does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

DELETE

/v5/webhook/{webhookKey}

Delete a webhook

Deletes a previously-registered webhook. This is irreversible.

Response

200 (OK)
Content-Type: application/json
{
    "statusCode"           : 200,
    "statusMessage"        : "Webhook deleted.",
    "statusTime"           : "1971-01-01T00:00:00.000Z",
}

Response

401 (Unauthorized)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 401,
    "statusMessage" : "Unauthorized; missing or invalid API key.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}

Response

404 (Not Found)
content-type: application/json; charset=utf-8
{
    "statusCode"    : 404,
    "statusMessage" : "Request failed; webhook does not exist.",
    "statusTime"    : "1971-01-01T00:00:00.000Z"
}