API Specification

Introduction

This specification documents the API as it is currently implemented. This file, and other associated documentation, will be updated as the API changes and is added to.

Posting XML API Requests

You must have a valid account in order to use the XML API.

The API URL is:

https://api.stgi.net/api-xml

Invoking this URL must be done by an HTTP POST.

Posting Forms and Authentication

Prior to calling other API functions, a call to GetAuthTokenRequest must be made to get an authentication token for subsequent calls.

For the GetAuthTokenRequest, the required post variables will be email, password, and xml.

(Note: these form variable names are case sensitive)

Example:

<form action="https://api.stgi.net/api-xml" method="post">
    <input type="hidden" name="email" value="myemail@email.com">
    <input type="hidden" name="password" value="mypassword234">
    <input type="hidden" name="xml" value="(URI encoded XML for GetAuthTokenRequest goes here)">
</form>

(note: you would not want to put your password in the clear on a real web page)

For other requests, the post variables would be email, auth_token and xml.

The auth_token would be the token returned from the GetAuthTokenRequest call in GetAuthTokenResponse.

Example:

<form action="https://api.stgi.net/api-xml" method="post">
    <input type="hidden" name="email" value="myemail@email.com">
    <input type="hidden" name="auth_token" value="(auth token returned in previous call)">
    <input type="hidden" name="xml" value="(URI encoded XML for your request goes here)">
</form>

XML Function Format

Each XML function will have a Request which is used as input and a Response. The general format of these are:

Requests

<FunctionnameRequest>
.
.
(Parameters vary per function)
.
.
</FunctionnameRequest>

Responses

Responses vary depending on whether the function call was successful or not. In the event of a failure, the response is standard across function calls and is shown below. Since these are similar across function calls, only successful responses will be shown in the individual API functions.

Successful Response

<FunctionnameResponse>
    <Result>Success</Result>
    .
    .
    (Output data varies per function)
    .
    .
</FunctionnameResponse>

Unsuccessful Response

<FunctionnameResponse>
    <Result>Error</Result>
    <ErrorCode>(A numeric error code)</ErrorCode>
    <ErrorText>(Text for this particular error)</ErrorText>
</FunctionnameResponse>

Input Parser

The parser used by the API server to process the input data is a XML parser. Only XML entities are supported, HTML entities are not supported.

For example, &pound; sign will trigger an "Your XML is valid, however, we do not recognize the top-level request element..." response from the API server. &#163; should be used instead.

For input elements that support HTML output, the ampersand sign can be escaped so that it could be shown properly in the web app. For example, &amp;pound;

Example request:

<AddTicketUpdateRequest ticket_id='50'>
    <TicketUpdate>
        <ContactID>123</ContactID>
        <Detail>&lt;p&gt;The total amount should be &#163;50.00. The grand total is &amp;pound;150.00.&lt;/p&gt;</Detail>
        <Status>Open</Status>
        <EmailClient>N</EmailClient>
        <EmailSupportTeam>N</EmailSupportTeam>
    </TicketUpdate>
</AddTicketUpdateRequest>

Basic XML entities are supported, they are:

Reference list can be found here.

API Functions

GetAuthTokenRequest

This function generates an auth token to be used in subsequent XML API calls.

The auth token issued does not expire.

To create an auth token that expires, pass the 'expiryMinutes' argument in the GetAuthTokenRequest XML.

If an XML API call returns an expired token error, a new one can be fetched by calling GetAuthTokenRequest again with the email and password for the account.

To return additional data in GetAUthTokenResponse, pass the showMore argument.

Input

Output

Example Request

<GetAuthTokenRequest></GetAuthTokenRequest> 

Successful Response

<GetAuthTokenResponse>
    <Result>Success</Result>
    <Token>(returned auth token)</Token>
</GetAuthTokenResponse>

Example Request (Creating an auth token that expires)

<GetAuthTokenRequest expiryMinutes="30"></GetAuthTokenRequest> 

Successful Response

<GetAuthTokenResponse>
    <Result>Success</Result>
    <Token>(returned auth token)</Token>
    <IssuedAt>1692978467</IssuedAt>
    <ExpiresIn>1800</ExpiresIn>
</GetAuthTokenResponse>

Example Request (To know if token is an account owner or shared access user)

<GetAuthTokenRequest showMore="true"></GetAuthTokenRequest> 

Successful Response

<GetAuthTokenResponse>
    <Result>Success</Result>
    <Token>(returned auth token)</Token>
    <IsOwner>Y</IsOwner>
</GetAuthTokenResponse>

GetAuthTokenRequest curl example:

curl -d "email=me@example.com&password=foobar&xml=<GetAuthTokenRequest />" https://api.stgi.net/api-xml

This is a curl example that calls the GetAuthTokenRequest API endpoint.

curl -d "email=me@example.com&password=foobar&xml=<GetAuthTokenRequest expiryMinutes="30"/>" https://api.stgi.net/api-xml

This is a curl example that calls the GetAuthTokenRequest request to create an auth token that expires in 30 minutes.

Accessing API As Power User

Power users (not an account owner) shares the same permission level as an account owner.

To make a user a power user, login to the web app. Go to Settings > Shared Access. Then click on the 'power users' link to add an user email as a power user.

For power users, calling the API requires that the account number to be passed.

If account number is not provided when it is required, the API will return an error similar to:

<Result>Error</Result>
<ErrorCode>1013</ErrorCode>
<ErrorText>Not an account owner and no account id found in xml</ErrorText>

Account number can be fetched by calling the <GetAccountsWithAccessRequest/> API after the auth token has been obtained from <GetAuthTokenRequest/>.

Examples of <GetAccountsWithAccessRequest/> usage can be found in the Users documentation.

After obtaining account number, pass the account number into the XML request tag in the 'account_id' parameter. For example:

<GetContactsRequest account_id="<ACCOUNT_ID>"></GetContactsRequest>

Caveat: Not all API accepts the 'account_id' parameter in the XML request parent tag. Some API calls require that the 'account_id' argument to be passed down in the child(ren) element. For example:

<AddContactsRequest>
    <Contacts>
        <Contact account_id="123456">
.
.
.
</AddContactsRequest>

Refer to each API documentation on how to pass the 'account_id' parameter.

Accessing API As Shared Access User

For shared access user (not an account owner), calling the API requires that the account number to be passed.

If account number is not provided when it is required, the API will return an error similar to:

<Result>Error</Result>
<ErrorCode>1013</ErrorCode>
<ErrorText>Not an account owner and no account id found in xml</ErrorText>

Account number can be fetched by calling the <GetAccountsWithAccessRequest/> API after the auth token has been obtained from <GetAuthTokenRequest/>.

Examples of <GetAccountsWithAccessRequest/> usage can be found in the Users documentation.

Other than returning the account number, the <GetAccountsWithAccessRequest/> API also returns information about the account limitation of the shared access user:

After obtaining account number, pass the account number into the XML request tag in the 'account_id' parameter. For example:

<GetContactsRequest account_id="<SHARED_ACCESS_USER_ACCOUNT_ID>"></GetContactsRequest>

Caveat: Not all API accepts the 'account_id' parameter in the XML request parent tag. Some API calls require that the 'account_id' argument to be passed down in the child(ren) element. For example:

<AddContactsRequest>
    <Contacts>
        <Contact account_id="123456">
.
.
.
</AddContactsRequest>

Refer to each API documentation on how to pass the 'account_id' parameter.

Fetching API Response In JSON Format

The API server supports response to be returned in JSON format. To do so, just pass the response="json" parameter into each request in the XML header.

For example, passing the response="json" in GetGroupsRequest header XML:

<GetGroupsRequest response="json"></GetGroupsRequest>

This will yield a JSON response:

{  
   "getgroupsresponse":{  
      "groups":{  
         "group":[  
            {  
               "group_type":"Private",
               "accountnumber":"38193",
               "group_id":"1",
               "includeloginlink":"Yes",
               "emailphysicaladdress":"",
               "emailssentfromemail":"test@test.org",
               "emailssentfromname":"Test",
               "name":"My Group",
               "totalmatchingcontacts":"15"
            },
            {  
               "group_type":"Private",
               "accountnumber":"38193",
               "group_id":"2",
               "includeloginlink":"No",
               "emailphysicaladdress":"",
               "emailssentfromemail":"",
               "emailssentfromname":"",
               "name":"No Contact Access",
               "totalmatchingcontacts":"7"
            },
            {  
               "group_type":"Private",
               "accountnumber":"38193",
               "group_id":"6",
               "includeloginlink":"No",
               "emailphysicaladdress":"",
               "emailssentfromemail":"",
               "emailssentfromname":"",
               "name":"Social Users",
               "totalmatchingcontacts":"1"
            }
         ]
      },
      "result":"Success"
   },
   "@encoding":"UTF-8",
   "@version":"1.0"
}

request_id Token Passthrough

The API server has a 'request_id' parameter passthrough feature that can be used to match/identify the request data to the response data.

All Add/Edit/Delete APIs that require XML list elements to be passed in the request have the 'request_id' parameter support. They are indicated in the API documentation in each their own Input section.

For example, to match the contacts in the request to the contacts in the response:

<AddContactsRequest>
    <Contacts>
        <Contact request_id="12345">
        ...
        </Contact>
        <Contact request_id="23456">
        ...
        </Contact>
    </Contacts>
</AddContactsRequest>

The corresponding response would be:

<AddContactsResponse>
    <Contacts>
        <Contact request_id="12345">
          <Result>Success</Result>
          ...
        </Contact>
        <Contact request_id="23456">
          <Result>Error</Result>
          <ErrorCode>1020</ErrorCode>
          ...
        </Contact>
    </Contacts>
</AddContactsResponse>

If response="json" is passed, the corresponding response would be:

{
    "@encoding": "UTF-8",
    "@version": "1.0",
    "addcontactsresponse": {
        "contacts": {
            "contact": [
                {
                    "@request_id": "12345",
                    "result": "Success",
                    ...
                },
                {
                    "@request_id": "23456",
                    "result": "Success",
                    ...
                }
            ]
        }
    }
}

API Rate Limit

The API server has a 300 requests per minute per account rate limit. An error message of 'Too many requests, 300 per minute max' will be returned if the limit has been reached.

Table Of Contents

TLS Version Support

We recently disabled TLS 1.0 on our SSL-offload load balancers. TLS 1.0 is currently considered weak and as a requirement for PCI compliance, it should be disabled. The currently allowed ciphers are below. If your HTTP client is having trouble connecting, please investigate updating your tools to support TLS 1.1 or TLS1.2.


PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   TLSv1.1: 
|     ciphers: 
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong
|     compressors: 
|       NULL
|   TLSv1.2: 
|     ciphers: 
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - strong
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - strong
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - strong
|     compressors: 
|       NULL
|_  least strength: strong